【问题标题】:C# Improvement on a Fire-and-ForgetC# 对即发即弃的改进
【发布时间】:2010-03-31 14:46:05
【问题描述】:

问候

我有一个程序可以创建一个类的多个实例,在所有实例上运行相同的长时间运行的 Update 方法并等待完成。我正在遵循 this question 的 Kev 方法,将更新添加到 ThreadPool.QueueUserWorkItem

在主程序中,我睡了几分钟,然后检查最后一个孩子的布尔值是否完成

while(!child[child.Length-1].isFinished) {
    Thread.Sleep(...);
}

此解决方案按我想要的方式工作,但有更好的方法吗?对于独立实例和检查是否所有工作都已完成。

谢谢

更新: 不需要锁定。不同的实例每个都有不同的 Web 服务 URL,它们从它们请求,并在响应上做类似的工作。他们都在做自己的事。

【问题讨论】:

    标签: c# optimization fire-and-forget


    【解决方案1】:

    如果您知道将要执行的操作次数,请使用倒计时和事件:

    Activity[] activities = GetActivities();
    int remaining = activities.Length;
    using (ManualResetEvent finishedEvent = new ManualResetEvent(false))
    {
        foreach (Activity activity in activities)
        {
            ThreadPool.QueueUserWorkItem(s =>
            {
                activity.Run();
                if (Interlocked.Decrement(ref remaining) == 0)
                    finishedEvent.Set();
            });
        }
        finishedEvent.WaitOne();
    }
    

    不要轮询完成。 .NET 框架(以及一般的 Windows 操作系统)有许多线程原语专门设计用于防止对自旋锁的需求,而带有Sleep 的轮询循环实际上只是一个缓慢的自旋锁。

    【讨论】:

      【解决方案2】:

      你可以试试Semaphore

      【讨论】:

      • 错了,你需要一个反向信号量(又名 CountdownLatch)。
      【解决方案3】:

      阻塞的等待方式比轮询更优雅一些。请参阅Monitor.Wait/Monitor.PulseSemaphore 也可以),了解一种简单的阻塞和信号方式。 C# 以 lock 关键字的形式围绕 Monitor 类提供了一些语法糖。

      【讨论】:

        【解决方案4】:

        这看起来不太好。几乎没有任何正当理由可以假设当最后一个线程完成时,其他线程也完成了。除非您以某种方式联锁工作线程,否则您永远不应该这样做。 Sleep() 也没有什么意义,等待线程完成。你也可以做那个线程正在做的工作。

        如果您有多个线程在运行,请给它们每个一个 ManualResetEvent。您可以使用 WaitHandle.WaitAll() 等待完成。使用 Interlocked 类倒计时线程计数器也可以工作。或者使用 CountdownLatch。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多