1

这可能是一个棘手的问题,但我所拥有的是一个包含 1000 行的 DataTable。Foreach 我想在新线程上处理这些行。但是我想将线程限制为 4 个线程。所以基本上我一直保持 4 个线程运行,直到整个数据表被处理。

目前我有这个;

  foreach (DataRow dtRow in urlTable.Rows)
        {
            for (int i = 0; i < 4; i++)
            {
                Thread thread = new Thread(() => MasterCrawlerClass.MasterCrawlBegin(dtRow));
                thread.Start();
            }
        }

我知道这是倒退的,但我不确定如何实现我想要的。我想到了一个非常复杂的 while 循环,但也许这不是最好的方法?任何帮助总是受到赞赏。

4

1 回答 1

6

最简单的解决方案是如果您有 4 个 CPU 内核 - 并行 LINQ +并行度 == 4 将为每个 CPU 内核提供一个线程,否则您必须在线程/任务之间手动分配记录,请参阅以下两种解决方案:

PLINQ 解决方案:

urlTable.Rows.AsParallel().WithDegreeOfParallelism(4)
             .Select(....)

手动分发:

您可以使用简单的技巧通过工作线程手动分配项目:N 线程将从N+4输入列表中获取每个项目,例如:

  • 第一个线程:每个0+4== 0、3、7...
  • 第二:每个1+4== 1、4、8 ...
  • 第三:每个2+4== ...

任务并行库解决方案:

private void ProcessItems(IEnumerable<string> items)
{
     // TODO: ..
}

var items = new List<string>(Enumerable.Range(0, 1000)
                                       .Select(i => i + "_ITEM"));
var items1 = items.Where((item, index) => (index + 0) % 4 == 0);
var items2 = items.Where((item, index) => (index + 1) % 4 == 0);
var items3 = items.Where((item, index) => (index + 2) % 4 == 0);
var items4 = items.Where((item, index) => (index + 3) % 4 == 0);

var tasks = new Task[]
    {
       factory.StartNew(() => ProcessItems((items1))),
       factory.StartNew(() => ProcessItems((items2))),
       factory.StartNew(() => ProcessItems((items3))),
       factory.StartNew(() => ProcessItems((items4)))
    };

Task.WaitAll(tasks);

MSDN:

于 2012-04-08T18:10:03.407 回答