【问题标题】:Best way to manage thread pool against database queue针对数据库队列管理线程池的最佳方法
【发布时间】:2011-11-17 00:09:38
【问题描述】:

我有一个充满汇总条目的数据表,我的软件需要通过网络服务获取详细信息,然后将这些详细信息记录回数据库。在调用 Web 服务并等待响应时同步循环遍历表太慢(有数千个条目),所以我想获取结果(一次大约 10 个)并将其线程化,以便执行 10同时进行操作。

我在 C# 线程方面的经验至少可以说是有限的,那么最好的方法是什么? .NET 是否有某种线程安全队列系统,我可以使用它来确保结果得到正确和有序的处理?

【问题讨论】:

  • 您使用的是什么版本的 .Net? .Net 4 中的多线程编程有了很大的改进。
  • 应该包括那个..目前的目标是 3.5,但我可以毫不费力地去 4.0。

标签: c# .net database winforms multithreading


【解决方案1】:

根据 .NET Framework 的版本,您有两个不错的选择。

您可以在任何版本中使用ThreadPool.QueueUserWorkItem

int pending = table.Rows.Count;
var finished = new ManualResetEvent(false);
foreach (DataRow row in table.Rows)
{
  DataRow capture = row; // Required to close over the loop variable correctly.
  ThreadPool.QueueUserWorkItem(
    (state) =>
    {
      try
      {
        ProcessDataRow(capture);
      }
      finally
      {
         if (Interlocked.Decrement(ref pending) == 0) 
         {
           finished.Set();  // Signal completion of all work items.
         }
      }
    }, null);
}
finished.WaitOne(); // Wait for all work items to complete.

如果您使用的是 .NET Framework 4.0,则可以使用 Task Parallel Library

var tasks = new List<Task>();
foreach (DataRow row in table.Rows)
{
  DataRow capture = row; // Required to close over the loop variable correctly.
  tasks.Add(
    Task.Factory.StartNew(
      () =>
      {
        ProcessDataRow(capture);        
      }));
}
Task.WaitAll(tasks.ToArray()); // Wait for all work items to complete.

还有许多其他合理的方法可以做到这一点。我强调了上面的模式,因为它们很简单而且效果很好。在没有具体细节的情况下,我不能肯定地说两者都适合您的情况,但它们应该是一个很好的起点。

更新:

我的大脑活动时间很短。如果您有可用的 TPL,您还可以使用 Parallel.ForEach 作为比我上面提到的所有 Task hocus-pocus 更简单的方法。

Parallel.ForEach(table.Rows,
  (DataRow row) =>
  {
    ProcessDataRow(row);
  });

【讨论】:

  • 顺便说一句,如果您从 Microsoft 网站下载 Reactive Extensions backport,您实际上可以在 3.5 中使用 TPL。
  • 很棒的东西——非常感谢大家。看起来有几种方法可以剥这只猫的皮!
  • 只有一件事(我知道,我会使用 RTFM!),但是这如何扩展?我将做数千个这样的行,我绝对不想同时启动数千个线程。我假设(希望?)内置了某种限制,因此这不会使用户的计算机停止运行。
  • @MitchellV: Thread.QueueUserWorkItemParallel.ForEach 可以很好地扩展。 Task.StartNew 通常可以很好地扩展,除了 Task.WaitAll 可能 如果它在幕后使用 WaitHandle.WaitAll 有 64 个计数限制,但我认为不会。所有这些方法都在其核心使用线程池技术,因此启动数千个工作项应该不是问题。
【解决方案2】:

.NET 是否有某种线程安全队列系统,我可以使用它来确保结果得到正确和有序的处理?

这是 .NET 4 中添加的内容。默认情况下,BlockingCollection&lt;T&gt; 类充当生产者/消费者场景的线程安全队列。

它可以相当容易地创建一些从集合和过程中“消耗”的元素,并将一个或多个元素添加到集合中。

【讨论】:

  • 非常好,我一定会去看看。谢谢!
  • @Dykam BlockingCollection&lt;T&gt;,默认情况下会包裹ConcurrentQueue&lt;T&gt;。虽然您可以直接使用 CQ,但如果您想在生产者/消费者场景中工作,如上所述,BC 使这变得相当简单。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-11
  • 1970-01-01
  • 2015-03-22
  • 2016-11-27
  • 1970-01-01
  • 2014-10-30
相关资源
最近更新 更多