Parallel.ForEach() 与 foreach(IEnumerable<T>.AsParallel())

Posted

技术标签:

【中文标题】Parallel.ForEach() 与 foreach(IEnumerable<T>.AsParallel())【英文标题】:Parallel.ForEach() vs. foreach(IEnumerable<T>.AsParallel()) 【发布时间】:2011-04-16 22:36:38 【问题描述】:

呃,我正在尝试使用 Reflector 在 BCL 中找到这两种方法,但找不到它们。这两个sn-ps有什么区别?

答:

IEnumerable<string> items = ...

Parallel.ForEach(items, item => 
   ...
);

乙:

IEnumerable<string> items = ...

foreach (var item in items.AsParallel())

   ...

使用其中一种会有不同的后果吗? (假设我在两个示例的括号中所做的任何事情都是线程安全的。)

【问题讨论】:

【参考方案1】:

他们做的事情完全不同。

第一个接受匿名委托,并在此代码上为所有不同的项目并行运行多个线程。

第二个在这种情况下不是很有用。简而言之,它旨在对多个线程进行查询,并将结果组合起来,然后再次将其提供给调用线程。因此,foreach 语句中的代码始终保留在 UI 线程上。

只有在 AsParallel() 调用右侧的 linq 查询中执行昂贵的操作时才有意义,例如:

 var fibonacciNumbers = numbers.AsParallel().Select(n => ComputeFibonacci(n));

【讨论】:

与简单地在 computefibonacci 上执行并行 foreach 相比有什么好处?【参考方案2】:

第二种方法不会并行,在您的示例中使用 AsParallel() 的正确方法是

IEnumerable<string> items = ...

items.AsParallel().ForAll(item =>

    //Do parallel stuff here
);

【讨论】:

为什么要结合使用 asparallel 和 forall 而不是简单的 foreach?【参考方案3】:

不同的是,B 不是平行的。 AsParallel() 所做的唯一事情是它包裹了 IEnumerable,因此当您使用 LINQ 方法时,会使用它们的并行变体。包装器的GetEnumerator()(在foreach 的幕后使用)甚至返回原始集合的GetEnumerator() 的结果。

顺便说一句,如果您想查看 Reflector 中的方法,AsParallel()System.Core 程序集中的 System.Linq.ParallelEnumerable 类中。 Parallel.ForEach()mscorlib 程序集中(命名空间 System.Threading.Tasks)。

【讨论】:

你的意思是……他们的平行变种被使用了……? @punctuation 例如,当您编写.Select() 时,它调用ParallelEnumerable.Select() 而不是正常的Enumerable.Select()

以上是关于Parallel.ForEach() 与 foreach(IEnumerable<T>.AsParallel())的主要内容,如果未能解决你的问题,请参考以下文章

Parallel.ForEach 与 Task.Factory.StartNew

Task.StartNew() 与 Parallel.ForEach :多个 Web 请求场景

在 .NET 3.5 中将 Parallel.Foreach 与分区器一起使用

Asp.Net 中有没有办法与运行 Parallel.Foreach 的后台线程进行通信

Parallel.ForEach 之 MaxDegreeOfParallelism

由于 HttpClient 请求缓慢,Task.Result 在 Parallel.ForEach 内阻塞