最高のパフォーマンスでC#のスレッドセーフカウンターを取得する方法は何ですか?
これは簡単です:
public static long GetNextValue()
{
long result;
lock (LOCK)
{
result = COUNTER++;
}
return result;
}
しかし、より高速な代替手段はありますか?
他の人が推奨するように、Interlocked.Increment
のパフォーマンスはlock()
よりも優れています。 Increment
が「バスロック」ステートメントになり、変数が直接インクリメント(x86)または「x64」に「追加」されることがわかるILとアセンブリを見てください。
この「バスロック」ステートメントは、呼び出し元のCPUが操作を実行している間、別のCPUがバスにアクセスできないようにバスをロックします。次に、C#lock()
ステートメントのILを見てください。ここでは、セクションを開始または終了するためのMonitor
の呼び出しが表示されます。
つまり、.Net lock()
ステートメントは、.Net Interlocked.Increment
よりも多くのことを行います。
ですから、変数をインクリメントするだけなら、Interlock.Increment
が高速になります。インターロックされたすべてのメソッドを確認して、使用可能なさまざまなアトミック操作を確認し、ニーズに合った操作を見つけます。相互に関連する複数の増分/減分など、より複雑なことを行う場合、または整数よりも複雑なリソースへのアクセスをシリアル化する場合は、lock()
を使用します。
System.Threadingライブラリで.NETの組み込みインターロックインクリメントを使用することをお勧めします。
次のコードは、参照によってlong変数をインクリメントし、完全にスレッドセーフです。
Interlocked.Increment(ref myNum);
Interlocked.Increment で試してください