c# task




Parallel.ForEach vs Task.Factory.StartNew (3)

Parallel.ForEach会优化(甚至不会启动新线程)并阻塞,直到循环结束,并且Task.Factory将为每个项目显式创建一个新的任务实例,并在完成之前返回(异步任务)。 Parallel.Foreach更高效。

下面的代码片段有什么区别? 不会都使用线程池线程?

例如,如果我想调用集合中每个项目的函数,

Parallel.ForEach<Item>(items, item => DoSomething(item));

vs

foreach(var item in items)
{
  Task.Factory.StartNew(() => DoSomething(item));
}

在我看来,最现实的情况是任务完成的任务繁重。 Shivprasad的方法更侧重于对象创建/内存分配而不是计算本身。 我做了一项研究,调用以下方法:

public static double SumRootN(int root)
{
    double result = 0;
    for (int i = 1; i < 10000000; i++)
        {
            result += Math.Exp(Math.Log(i) / root);
        }
        return result; 
}

该方法的执行时间约为0.5秒。

我用Parallel命名了它200次:

Parallel.For(0, 200, (int i) =>
{
    SumRootN(10);
});

然后我用老式的方式称它200次:

List<Task> tasks = new List<Task>() ;
for (int i = 0; i < loopCounter; i++)
{
    Task t = new Task(() => SumRootN(10));
    t.Start();
    tasks.Add(t);
}

Task.WaitAll(tasks.ToArray()); 

第一个案件在26656ms完成,第二个案件在24478ms完成。 我重复了很多次。 每次第二种方法边际化速度更快。


第一个是更好的选择。

Parallel.ForEach在内部使用Partitioner<T>将您的集合分发到工作项目中。 它不会为每个项目执行一项任务,而是批量执行此项以降低涉及的开销。

第二个选项将为您的收藏中的每个项目安排一个单独的Task 。 尽管结果会(几乎)相同,但这会带来比必要的更多的开销,特别是对于大型集合,并导致整体运行时间变慢。

仅供参考 - 如果需要,可以使用适用于Parallel.ForEach的重载来控制所使用的分区程序。 有关详细信息,请参阅MSDN上的自定义分区程序

主要的区别是,在运行时,第二个是异步的。 这可以通过使用Parallel.ForEach进行复制:

Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));

通过这样做,您仍然可以利用分区程序,但在操作完成之前不会阻塞。





parallel-extensions