Semaphore 和 SemaphoreSlim 使用最佳实践

问题描述 投票:0回答:2

我在这个类之上创建了一个信号量实例

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-我如何使用这个细长的信号量来控制数据使用(平衡、隔离线程等)?

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

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

更新: 我在很久以前做的一份工作中问过这个问题。解决问题后我发现我没有回来。

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

问题是:如果线程不能让我了解它正在做什么,如果它不能告诉我它是否取得了成功的结果,我为什么要使用线程?例如,为什么我应该使用 SemaphoreSlim!?

是的,当然可以通过异步编程来完成。但我不想将该库包含在相关环境中。必须如此。我确信很多代码都需要这种情况。

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

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

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

c# multithreading semaphore
2个回答
4
投票

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

至少这个代码:

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

应至少为:

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

否则,如果

DoSomeThing()
发生异常,您最终可能永远不会再释放信号量。

在异步编程中,考虑使用:

await semaphore.WaitAsync();

2
投票

信号量结束其所有线程时是否有任何事件

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

信号量无法检测到这种情况,因为与每个正在执行的线程不同。

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

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


顺便说一句,您发布的代码在其他方面也是可疑的:

  1. 为什么要为
    SemaphoreSlim
    指定最大计数,为什么这个最大值与您的初始计数不同?您实际上期望拨打
    Release()
    的次数比拨打
    Wait()
    的次数多吗?
  2. 调用
    Thread.Sleep()
    的代码通常是不正确的。目前尚不清楚您为什么要这样做,但很可能有更好的方法来解决您试图通过这些电话解决的任何问题。

如果没有一个好的最小、完整和可验证的示例,我不能肯定地说这些事情是错误的。但他们正确的可能性很小。 :)

© www.soinside.com 2019 - 2024. All rights reserved.