Semaphore 和 SemaphoreSlim 使用最佳实践

Semaphore and SemaphoreSlim usage Best Practices

我在此基础上创建了一个信号量实例 class

public static SemaphoreSlim _zReportSemaphore = new SemaphoreSlim(1, 500);

在我的代码中某处我需要检索和发送一些数据。

while (_isRunning)
{
    try
    {
        xBsonDocument = null;
        //I think its very clear in this line...
        MongoDBDAO.xGetInstance().GetZReportData(ref xBsonDocument);

        foreach (BsonDocument item in xBsonDocument)
        {
            try
            {
                ThreadObject xThreadObject = new ThreadObject();
                xThreadObject.m_strTerminalId = item.GetValue("_id")["TERMINAL_ID"].ToString();
                xThreadObject.m_strZNo = item.GetValue("_id")["Z_NO"].ToString();

                m_xBuildAndSendZReportThread = 
                    new Thread(new ParameterizedThreadStart(vBuildAndSendZReport));
                m_xBuildAndSendZReportThread.Start(xThreadObject);
            }
            catch (Exception xException)
            {
                xException.TraceError();
                continue;
            }

            Thread.Sleep(m_litleStepQTime); 
        }
    }
    catch (Exception xException)
    {
        Thread.Sleep(m_bigStepQTime);
        Trace.vInsertError(xException);
        continue;
    }

    Thread.Sleep(m_iSleepTime);
}

此主题旨在将文件发送至 ftp

        private void vBuildAndSendZReport(object prm_objParameters)
        {
            _zReportSemaphore.Wait();
            RetriveDataFromMongoAndSend();
            _zReportSemaphore.Release();
        }

在这个结构中;如果我不使用信号量,它会工作得很好,但有时线程数会使 CPU 或内存使用量过载,并且机器已经崩溃。

1- 我如何使用这个 slim 信号量来控制数据使用(平衡、隔离线程等)?

2- 我可以将 SemaphoreSlim 用于生产中的此类工作吗?使用这样的工作流组织有哪些优点和缺点? 它会提高性能吗?在我的特殊情况下

3- 是否有另一种替代方案可以提供系统资源管理并结束技术异常管理

更新: 我在很久以前做的工作中问过这个问题。解决问题后才发现我没有return.

在上面的示例中,报告发送作业发生在文件共享环境中。其他解决方案也是可能的,例如使用 CDN。

问题是:如果线程不能让我知道它在做什么,如果它不告诉我它是否已经取得成功,我为什么要使用线程?我为什么要用 SemaphoreSlim 为例!?

是的,当然可以用异步编程来完成。但我不想将这个库包含在相关环境中。它必须是。我敢肯定很多代码都需要这种情况。

我的解决方案是这样的:我消除了抛出异常的代码中出现异常的可能性。所以我将冲突与应用程序外部的线程同步。我做了一个线程池之类的东西。它作为消费者完美地工作。我通过设置自定义计时机制来做到这一点。

不管怎样,我还是同意的。应该设置一个线程来携带有关它正在执行的工作的信息。我不是在谈论在两者之间编写 Mutex 对象。线程本身可以承载这些信息。

顺便给回答的人加分。因为他们根据问题给出了正确的评论。

Is there any event when semaphore ends its all threads

没有。甚至不清楚这可能意味着什么。例如,如果由于线程调度问题,此时信号量中只有一个 运行ning 线程,并且该线程在一个或多个其他线程之前完成并释放信号量,您希望发生什么线程甚至可以尝试获取信号量?

信号量无法检测到这种情况,因为每个线程都在完成。

如果您想知道某些异步操作集合何时完成,您需要专门等待。您在 .NET 中有多种选择,包括:

  1. 对您启动的所有线程对象调用 Thread.Join()
  2. 使用 Task 来 运行 您的异步任务而不是 Thread,并使用 Task.WhenAll()(或者更不理想,Task.WaitAll())来等待它们完成。
  3. 使用CountdownEvent。为您开始的每个任务调用 AddCount(),让每个任务在完成时调用 Signal(),然后等待 CountdownEvent.


顺便说一下,您发布的代码在其他方面存在问题:

  1. 为什么要为 SemaphoreSlim 指定最大计数,为什么这个最大值与初始计数不同?你真的希望调用 Release() 比你调用 Wait() 更频繁吗?
  2. 调用 Thread.Sleep() 的代码通常不正确。目前尚不清楚您这样做的原因,但很可能有更好的方法来解决您试图通过这些调用解决的任何问题。

没有好的Minimal, Complete, and Verifiable example,我不能肯定地说那些东西是错的。但他们是对的可能性很小。 :)

这是“Semaphore 和 SemaphoreSlim 使用最佳实践”在 Google 上的第一次点击,所以我想补充 1 条评论:

至少,这段代码

    semaphore.Wait();
    DoSomeThing();
    semaphore.Release();

应该是最小值

    semaphore.Wait();
    try
    {
        DoSomeThing();
    }
    finally
    {
        semaphore.Release();
    }

否则,如果在 DoSomeThing 中发生异常,您可能最终再也不会释放信号量...

并且在异步编程中,考虑使用

    await semaphore.WaitAsync();