私はParallel.Forが次のようなシナリオで多くのスレッドより優れたパフォーマンスを発揮できる理由を理解しようとしています。並列処理できるジョブのバッチを考えてみましょう。これらのジョブを処理している間に、新しい作業が追加される可能性があります。新しい作業が処理される必要があります。以下のようになり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
コードは、もちろん非常にきれいですが、私が理解することはできません、それは同様であっても高速です!タスクスケジューラはそれだけでいいですか?同期は絶滅していました。待ち時間がなくなりましたが、スレッドアプローチは一貫して遅いです(私にとって)。どうしたの?スレッディングのアプローチをより速くすることはできますか?
編集:すべての回答ありがとう、私は複数のものを選ぶことができたらいいですね。私は実際の可能性のある改善を示すものと一緒に行くことにしました。
すでにクリーンなソリューションがあれば、なぜそれを速くしたいのですか? – iMortalitySX
明白な欠点が排除できるので、私は思います。 –
閉じる質問[PLinqは本質的にSystem.Threading.Tasks.Parallel.ForEachより高速ですか?](http://stackoverflow.com/questions/5196293/is-plinq-inherently-faster-than-system-threading-tasks-parallel- foreach) – iMortalitySX