我试图理解为什么 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
代码当然更简洁,但我无法理解的是,它甚至更快!任务调度程序就那么好吗?消除了同步,没有忙等待,但线程方法始终较慢(对我而言)。这是怎么回事?线程方法可以更快吗?
编辑:感谢所有的答案,我希望我可以选择多个。我选择了那个也显示出实际可能改进的那个。
最佳答案
这两个代码示例并不完全相同。
Parallel.ForEach()
将使用有限数量的线程并重新使用它们。第二个示例已经开始落后了,必须创建多个线程。这需要时间。
maxThreads
的值是多少?非常关键,在 Parallel.ForEach()
中它是动态的。
Is the task scheduler just that good?
还不错。 TPL 使用工作窃取和其他自适应技术。您将很难做得更好。
关于c# - Parallel.For 与常规线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13070339/