私はStriplingWarrorからのテストを使用して、その違いがどこから来ているかを調べました。私はこれを行いました。なぜなら、コードでReflectorを見ると、Parallelクラスはたくさんのタスクを作成して実行させることと何も変わりません。
理論的な観点からは、両方の方法が実行時間の点で同等である必要があります。しかし、空のアクションを持つ(あまり現実的ではない)テストでは、Parallelクラスがはるかに高速であることがわかりました。
タスクバージョンは、多くのガベージコレクションにつながる新しいタスクの作成にほとんど時間を費やしています。表示される速度の違いは、純粋にあなたがすぐにゴミになる多くのタスクを作成するという事実によるものです。
代わりに、Parallelクラスは、すべてのCPUで同時に実行される独自のタスク派生クラスを作成します。すべてのコアで実行されるphyiscalタスクは1つだけです。同期は、現在、タスクデリゲートの内部で行われていますが、これはParallelクラスのはるかに高速です。
ParallelForReplicatingTask task2 = new ParallelForReplicatingTask(parallelOptions, delegate {
for (int k = Interlocked.Increment(ref actionIndex); k <= actionsCopy.Length; k = Interlocked.Increment(ref actionIndex))
{
actionsCopy[k - 1]();
}
}, TaskCreationOptions.None, InternalTaskOptions.SelfReplicating);
task2.RunSynchronously(parallelOptions.EffectiveTaskScheduler);
task2.Wait();
だから何が良いですか?最良のタスクは決して実行されないタスクです。ガベージコレクタにとって負担になるような多くのタスクを作成する必要がある場合は、タスクAPIから離れ、新しいタスクなしですべてのコアで直接並列実行できるParallelクラスを使用してください。
あなたも速く、それは手でスレッドを作成して、アクセスパターンのためにあなたの最高速度を与えるために手最適化されたデータ構造を使用すると、最もパフォーマンスの高いソリューションであることかもしれませんになるために必要がある場合。しかし、TPL APIとParallel APIが既に大きく調整されているため、成功することはまずありません。通常は、多くのオーバーロードのうちの1つを使用して実行中のタスクを構成するか、Parallelクラスを使用してコードを大幅に少なくする必要があります。
しかし、標準以外のスレッドパターンを使用している場合は、コアを最大限に活用するためにTPLを使用しないほうがよい場合があります。スティーブン・トゥブ(Stephen Toub)も、TPL APIは超高速パフォーマンスのために設計されていないが、主な目的は「平均的な」プログラマのためのスレッド化を容易にすることであると述べました。特定のケースでTPLを克服するには、平均以上のものが必要であり、CPUキャッシュライン、スレッドスケジューリング、メモリモデル、JITコード生成などについて多くのことを知る必要があります。より良い。
私は彼らが多かれ少なかれ同等だと思う。あなたのプロファイラはあなたに何を伝えていますか? –
あなたはベンチマークを検討しましたか? –
2つの方法についてのこの素敵な小さな記事をチェックしてください:http://blackrabbitcoder.net/archive/2012/12/20/c.net-little-wonders-the-parallel.invoke-method.aspx。私はパフォーマンスの違いはないと思うが、私はParallel.Invokeが簡単だと思う。 –