当我在Parallel.ForEach
命名空间中使用Parallel.For
或System.Threading.Tasks
时,我可以假设所有线程在执行继续之前都已同步吗?
是否有相当于
的东西WaitHandle.WaitAll(...);
继续?
所以,如果我打电话给
Parallel.ForEach(collection, DoSomethingWithObject);
在 DoSomethingWithObject
返回之前,我可以确定每个ForEach
的来电已完成,还是我需要自己使用WaitHandles
?
答案 0 :(得分:3)
为了扩展Phong的正确答案,Parallel.For和Parallel.ForEach在内部创建了一个所谓的ParallelXXXReplicationTask,它同步运行并产生X个子任务,其中X是有效的并发级别(默认为Environment.ProcessorCount)。每个子任务与Semphore同步,Semphore一旦设置(计数为0)就释放父任务,这确保父任务的执行仅在所有子任务完成后(或通过同步设置确定崩溃/停止)返回。由于parentTask是同步运行的并且正在等待。您可以确保无论何时对Parallel方法的调用返回,所有迭代都已有效完成。
答案 1 :(得分:2)
所有任务都将在Parallel.ForEach()
返回时完成,除非专门调用Stop()
来中止并行执行。在这种情况下,.IsCompleted
返回的ParallelLoopState
对象的Parallel.ForEach()
属性将为false
。
你可以在这里阅读:
http://msdn.microsoft.com/en-us/library/dd992001.aspx
http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallelloopresult.aspx
您还可以编写一个小型测试应用程序,其中DoSomethingWithObject()
是一个长时间运行的操作,或者是对Thread.Sleep()
的调用,以验证这一点。执行将阻塞,直到所有线程都完成睡眠。
样品:
Parallel.ForEach(Enumerable.Range(1, 8),
i =>
{
Thread.Sleep(5000);
Console.WriteLine(i + " done!");
});
Console.WriteLine("All done!");
答案 2 :(得分:2)
我可以确定每次调用DoSomethingWithObject都已完成 在ForEach返回之前,还是我需要自己使用WaitHandles?
Parallel.ForEach
是一个阻止通话。在每次迭代完成之前,它不会返回。
是否有等同于
WaitHandle.WaitAll(...);
的内容?
是的,或多或少。它实际上不会使用WaitHandle.WaitAll
,因为1)它会非常低效; 2)它不具有可伸缩性,因为它有64个句柄限制。有一些非常可扩展的技术可用于等待完成多个任务。我最喜欢的一个是使用CountdownEvent
。 1
以下是它的工作原理。用你的想象力假装Parallel.ForEach
扩展为以下代码。 2
var finished = new CountdownEvent(1);
foreach (var item in collection)
{
var capture = item;
finished.AddCount();
Task.Factory.StartNew(
() =>
{
try
{
DoSomething(capture);
}
finally
{
finished.Signal();
}
});
}
finished.Signal();
finished.Wait();
1 我不是说这是Parallel.ForEach
使用的技术,但它可能类似。
2 实际上Parallel.ForEach
以更复杂的方式实施。我只是想帮助您想象它可能等待每次迭代完成的时间。
答案 3 :(得分:0)
Parallel.ForEach()
和Parallel.For()
将阻止其所有任务结束,原因是它们已成功完成或因为已取消。所以是的,所有线程在执行继续之前都是同步的。