最近、C#.net4に移動しました。
Parallel.Forが大好きですが、いつ使用するか、いつ使用しないかはわかりません。順序が私にとって重要でない場合、私はそれを使用することを知っています。
しかし、Parallelsでの作業のオーバーヘッドに関するテストはありますか?つまり、ループが10回しか実行されない(そしてロジックをほとんど実行しない)場合、Parallelsを避ける必要がありますか?経験則はありますか?
Parallel.Forパフォーマンスが問題にならない限り、使用は避けます。
同時に実行されるコードを作成することは、一般に、シングルスレッドコードを作成するよりも困難です。さらに、同時実行の問題が原因でエラーが発生した場合、デバッグが困難になる可能性があります。たとえば、バグはたまにしか発生せず、簡単に再現できない場合があります。パフォーマンスを向上させる必要が特にない限り、シンプルに保ち、単一スレッドで通常のループを使用することをお勧めします。
Parallel.Forループは、ThreadPoolを使用して、ループの反復ごとに1回デリゲートを呼び出すことにより、ループ内で作業を実行します。
Parallel.Forがどのように機能するかについての一般的な考え方は、次のように表すことができます。
public static void MyParallelFor(int inclusiveLowerBound, int exclusiveUpperBound, Action<int> body)
{
// Get the number of processors, initialize the number of remaining
// threads, and set the starting point for the iteration.
int numProcs = Environment.ProcessorCount;
int remainingWorkItems = numProcs;
int nextIteration = inclusiveLowerBound;
using (ManualResetEvent mre = new ManualResetEvent(false))
{
// Create each of the work items.
for (int p = 0; p < numProcs; p++)
{
ThreadPool.QueueUserWorkItem(delegate
{
int index;
while ((index = Interlocked.Increment(ref nextIteration) - 1) < exclusiveUpperBound)
body(index);
if (Interlocked.Decrement(ref remainingWorkItems) == 0)
mre.Set();
});
}
// Wait for all threads to complete.
mre.WaitOne();
}
}
Parallel.Forは、完了したループの詳細を含むParallelLoopResult値型を返します。その過負荷の1つは次のとおりです。
public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body);
並列実行は必ずしも直列実行よりも高速であるとは限らないことを理解することが重要です。並列を使用するかどうかを決定するには、ループの反復ごとに実行されるワークロードを見積もる必要があります。ループによって実行される実際の作業がスレッド同期コストに比べて小さい場合は、通常のループを使用することをお勧めします。
これは、シリアルforループのパフォーマンスがパラレルよりも高速な場合の例の1つです。
static void Main(string[] args)
{
Action<int> action = new Action<int>(SimpleMethod);
// ordinary For loop performance estimation
var sw = Stopwatch.StartNew();
for(int i = 0; i < 1000; i++)
action(i);
Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds);
// parallel For loop performance estimation
sw = Stopwatch.StartNew();
Parallel.For(0, 1000, action);
Console.WriteLine("{0} sec.", sw.Elapsed.TotalSeconds);
}
static void SimpleMethod(int index)
{
int d = 1;
int result = index / d;
}
出力:
0.0001963 sec.
0.0346729 sec.
SQLite FAQの引用:'スレッドは悪です。それらを避けてください」
並列化はパフォーマンスに役立ちます。アプリケーションのパフォーマンスの最適化は、ソフトウェア設計で最も直感に反することの1つであり、適切な測定ツールを使用して細心の注意を払って実行する必要があります。そうしないと、見た目がおかしくなります。
UIコードを最適化して、ミリ秒ではなくマイクロ秒で応答するものもありますが、明らかに価値がなく、多くの損害を引き起こします。