管理数据库队列的线程池的最佳方法

时间:2011-11-17 00:09:39

标签: c# .net database winforms multithreading

我有一个包含摘要条目的数据表,我的软件需要通过并访问Web服务以获取详细信息,然后将这些详细信息记录回数据库。在调用Web服务并等待响应时同步循环遍历表太慢(有数千个条目)所以我想取结果(一次10个左右)并将其解压缩以使其执行10同时进行操作。

我对C#线程的体验至少可以说,所以最好的方法是什么? .NET是否有某种线程安全队列系统,我可以用它来确保结果得到正确处理并按顺序排列?

2 个答案:

答案 0 :(得分:5)

  

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

这是在.NET 4中添加的内容。默认情况下,BlockingCollection<T>类充当生产者/消费者方案的线程安全队列。

通过将一个或多个元素添加到集合中,可以非常轻松地创建从集合和流程中“消耗”的多个元素。

答案 1 :(得分:5)

根据.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);
  });