以下のコードスニペットの違いは何ですか?どちらもスレッドプールスレッドを使用していませんか。
たとえば、コレクション内の各項目に対して関数を呼び出したい場合は、
Parallel.ForEach<Item>(items, item => DoSomething(item));
vs
foreach(var item in items)
{
Task.Factory.StartNew(() => DoSomething(item));
}
最初の方がはるかに良い選択肢です。
Parallel.ForEachは、内部的にPartitioner<T>
コレクションを作業項目に配布するため。アイテムごとに1つのタスクを実行するのではなく、関連するオーバーヘッドを減らすためにこれをバッチ処理します。
2番目のオプションは、単一のTask
あなたのコレクションのアイテムごとに。結果は(ほぼ)同じになりますが、これは、特に大規模なコレクションの場合、必要以上にはるかに多くのオーバーヘッドをもたらし、全体的なランタイムを遅くします。
FYI - 使用されるPartitionerは適切なものを使用して制御できます。Parallel.ForEachへのオーバーロード必要に応じて。詳しくは、カスタムパーティショナMSDNで。
主な違いは、実行時には、2番目に非同期で動作することです。これは、Parallel.ForEachを使用して次のようにして複製できます。
Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));
こうすることで、まだパーティショナーを利用できますが、操作が完了するまでブロックしないでください。
Parallel.ForEachはループが終了するまで最適化し(新しいスレッドを開始することすらできません)、ブロックします。そしてTask.Factoryは各項目に対して新しいタスクインスタンスを明示的に作成し、終了する前に戻ります(非同期タスク)。 Parallel.Foreachははるかに効率的です。
私は "Parallel.For"と "Task"オブジェクトを使って "1000000000"メソッドを実行する小さな実験をしました。
プロセッサ時間を測定したところ、Parallelの方が効率的でした。 Parallel.Forはあなたのタスクを小さなワークアイテムに分割し、それらをすべてのコアで最適な方法で並行して実行します。多くのタスクオブジェクトを作成している間(FYI TPLは内部的にスレッドプールを使用します)、各タスクでのすべての実行を移動させ、ボックス内により多くのストレスをかけます。これは以下の実験から明らかです。
また、基本的なTPLを説明する小さなビデオを作成し、Parallel.Forがコアをより効率的に活用する方法も示しましたhttp://www.youtube.com/watch?v=No7QqSc5cl8通常のタスクやスレッドと比較して。
実験1
Parallel.For(0, 1000000000, x => Method1());
実験2
for (int i = 0; i < 1000000000; i++)
{
Task o = new Task(Method1);
o.Start();
}
Mehthod1()
この例ではどうですか? - Zapnologica
私の考えでは、最も現実的なシナリオは、タスクが完了するのに重い操作を持つときです。 Shivprasadのアプローチは、コンピューティング自体よりもオブジェクトの作成/メモリ割り当てに重点を置いています。私は以下の方法を呼び出す研究をしました:
public static double SumRootN(int root)
{
double result = 0;
for (int i = 1; i < 10000000; i++)
{
result += Math.Exp(Math.Log(i) / root);
}
return result;
}
このメソッドの実行には約0.5秒かかります。
Parallelを使って200回呼び出しました。
Parallel.For(0, 200, (int i) =>
{
SumRootN(10);
});
それから私は昔ながらの方法を使用してそれを200回呼び出しました:
List<Task> tasks = new List<Task>() ;
for (int i = 0; i < loopCounter; i++)
{
Task t = new Task(() => SumRootN(10));
t.Start();
tasks.Add(t);
}
Task.WaitAll(tasks.ToArray());
最初のケースは26656ms、2番目のケースは24478msで完了しました。私はそれを何度も繰り返しました。毎回2番目のアプローチが限界より速いです。