【发布时间】:2012-10-15 17:45:37
【问题描述】:
我试图理解为什么 Parallel.For 在以下场景中能够胜过多个线程:考虑可以并行处理的一批作业。在处理这些工作时,可能会添加新工作,然后也需要处理这些工作。 Parallel.For 解决方案如下所示:
var jobs = new List<Job> { firstJob };
int startIdx = 0, endIdx = jobs.Count;
while (startIdx < endIdx) {
Parallel.For(startIdx, endIdx, i => WorkJob(jobs[i]));
startIdx = endIdx; endIdx = jobs.Count;
}
这意味着 Parallel.For 需要多次同步。考虑一个面包优先的图算法算法;同步的数量会很大。浪费时间,不是吗?
在老式线程方法中尝试相同的方法:
var queue = new ConcurrentQueue<Job> { firstJob };
var threads = new List<Thread>();
var waitHandle = new AutoResetEvent(false);
int numBusy = 0;
for (int i = 0; i < maxThreads; i++)
threads.Add(new Thread(new ThreadStart(delegate {
while (!queue.IsEmpty || numBusy > 0) {
if (queue.IsEmpty)
// numbusy > 0 implies more data may arrive
waitHandle.WaitOne();
Job job;
if (queue.TryDequeue(out job)) {
Interlocked.Increment(ref numBusy);
WorkJob(job); // WorkJob does a waitHandle.Set() when more work was found
Interlocked.Decrement(ref numBusy);
}
}
// others are possibly waiting for us to enable more work which won't happen
waitHandle.Set();
})));
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());
Parallel.For 代码当然更干净,但我无法理解的是,它也更快!任务调度器就这么好吗?同步被消除了,没有忙碌的等待,但线程方法始终较慢(对我而言)。这是怎么回事?线程方法可以更快吗?
编辑:感谢所有答案,我希望我可以选择多个。我选择了那个也显示出实际可能改进的那个。
【问题讨论】:
-
如果已经有更干净、更快速的解决方案,为什么还要尝试让它更快?
-
因为有一个明显的缺陷可以消除,我认为。
-
您确实意识到代码的两个 sn-ps 就像白天和黑夜一样不同,对吧?一方面,您有一个静态的、已知数量的列表作业(在 startIdx 和 endIdx 之间)上的并行循环,另一方面,您有一组线程与队列和等待事件竞争,有几个互锁的传播介于两者之间。换句话说,线程代码是cache invalidation galore。
-
@Remus:谢谢,又一个好收获。
标签: c# multithreading performance