41

コードでスピンロックを実際に使用している頻度はどれくらいですか? ビジー ループを使用した方が実際にロックを使用した場合よりもパフォーマンスが優れているという状況に遭遇することは、どのくらいよくあることでしょうか?
個人的には、スレッド セーフが必要なコードを書くときは、さまざまな同期プリミティブを使ってベンチマークする傾向があります。その限りでは、スピンロックを使用するよりもロックを使用した方がパフォーマンスが向上するようです。実際にロックを保持している時間がどれだけ短いかに関係なく、スピンロックを使用した場合に発生する競合の量は、ロックを使用した場合よりもはるかに多くなります (もちろん、私はマルチプロセッサ マシンでテストを実行しています)。

「低レベル」のコードでスピンロックに遭遇する可能性が高いことは認識していますが、より高レベルの種類のプログラミングでも役立つかどうか知りたいですか?

4

10 に答える 10

40

それはあなたが何をしているかによります。一般的なアプリケーション コードでは、スピンロックを回避する必要があります。

数命令の間だけロックを保持し、レイテンシが重要な低レベルのものでは、ロックよりもスピンロックマットの方が優れたソリューションになります。ただし、特に C# が通常使用される種類のアプリケーションでは、そのようなケースはまれです。

于 2009-09-21T19:07:05.840 に答える
23

C# では、私の経験では、「スピン ロック」はほとんどの場合、ロックを取得するよりも悪いものでした。スピン ロックがロックよりもパフォーマンスが優れているのはまれです。

ただし、常にそうであるとは限りません。.NET 4 はSystem.Threading.SpinLock構造を追加しています。これは、ロックが非常に短時間保持され、繰り返し取得される状況で利点を提供します。並列プログラミングのデータ構造に関する MSDN ドキュメントから:

ロックの待機時間が短いことが予想されるシナリオでは、SpinLock は他の形式のロックよりも優れたパフォーマンスを提供します。

スピン ロックは、ツリーを介してロックするようなことを行う場合、他のロック メカニズムよりも優れたパフォーマンスを発揮します。非常に短い時間だけ各ノードをロックする場合は、従来のロックよりも優れたパフォーマンスを発揮します。ある時点で、マルチスレッド シーンの更新を伴うレンダリング エンジンでこれに遭遇しました。

于 2009-09-21T19:18:08.987 に答える
12

リアルタイムの作業、特にデバイス ドライバーでは、それらをかなり使用してきました。(最後にこれを計測したとき) ハードウェア割り込みに関連付けられたセマフォのような同期オブジェクトを待機すると、実際に割り込みが発生するのにどれだけ時間がかかっても、少なくとも 20 マイクロ秒かかることがわかりました。メモリ マップされたハードウェア レジスタの 1 回のチェックと、それに続く RDTSC のチェック (マシンをロックしないようにタイムアウトを許可するため) は、高いナノ秒の範囲内です (基本的にはノイズが少なくなります)。まったく時間がかからないハードウェア レベルのハンドシェイクの場合、スピンロックを打ち負かすのは非常に困難です。

于 2009-09-21T19:17:29.513 に答える
11

私の 2c: 更新がいくつかのアクセス基準を満たしている場合、それらは適切なスピンロック候補です。

  • fast、つまり、スピンロックを保持している間にプリエンプトされないように、スピンロックを取得し、更新を実行し、単一のスレッド クォンタムでスピンロックを解放する時間があります。
  • ローカライズされたすべてのデータは、できればすでにロードされている 1 つのページにあり、スピンロックを保持している間に TLB ミスが発生することは望ましくありません。
  • アトミック操作を実行するために他のロックは必要ありません。スピンロックの下でロックを待つことはありません。

生成される可能性があるものについては、通知されたロック構造 (イベント、ミューテックス、セマフォなど) を使用する必要があります。

于 2009-09-21T19:12:27.263 に答える
8

スピン ロックの使用例の 1 つは、競合が非常に少ないと予想されるが、多数の競合が発生する場合です。再帰ロックのサポートが必要ない場合は、スピンロックを 1 バイトで実装できます。競合が非常に少ない場合、CPU サイクルの無駄は無視できます。

実際の使用例として、配列のさまざまな要素への更新を安全に並行して行うことができる、何千もの要素の配列を使用することがよくあります。2 つのスレッドが同じ要素を同時に更新しようとする可能性は非常に低い (競合が少ない) が、すべての要素に対して 1 つのロックが必要です (多数の要素を使用する予定です)。これらの場合、私は通常、並行して更新している配列と同じサイズの ubytes の配列を割り当て、(D プログラミング言語で) 次のようにインラインでスピンロックを実装します。

while(!atomicCasUbyte(spinLocks[i], 0, 1)) {}
    myArray[i] = newVal;
atomicSetUbyte(spinLocks[i], 0);

一方、通常のロックを使用する必要がある場合は、オブジェクトへのポインターの配列を割り当ててから、この配列の各要素に Mutex オブジェクトを割り当てる必要があります。上記のようなシナリオでは、これは単なる無駄です。

于 2010-07-16T17:05:46.890 に答える
6

パフォーマンスが重要なコードがあり、現在よりも高速にする必要がある判断し、重要な要素がロック速度であると判断した場合は、スピンロックを試すことをお勧めします。他の場合では、なぜわざわざ?通常のロックは正しく使用する方が簡単です。

于 2009-09-21T19:44:46.310 に答える
5

次の点に注意してください。

  1. ほとんどのミューテックスの実装は、スレッドが実際にスケジュール解除される前に、少しの間スピンします。このため、これらのミューテックスを純粋なスピンロックと比較することは困難です。

  2. 同じスピンロックで「できるだけ速く」スピンする複数のスレッドは、すべての帯域幅を消費し、プログラムの効率を大幅に低下させます。スピニング ループに noop を追加して、小さな「スリープ」時間を追加する必要があります。

于 2009-09-21T19:31:07.193 に答える
3

アプリケーション コードでスピンロックを使用する必要はほとんどありません。

通常の OS で実行されている C# コードでスピンロックを使用する理由はありません。ビジーロックは、ほとんどの場合、アプリケーションレベルでは無駄です。回転すると、CPU タイムスライス全体を使用する可能性がありますが、ロックは必要に応じてコンテキストスイッチを即座に引き起こします。

nr of threads=nr of processor/cores の高性能コードは、場合によってはメリットがあるかもしれませんが、そのレベルでパフォーマンスの最適化が必要な場合は、次世代 3D ゲームを作成したり、同期プリミティブが不十分な組み込み OS で作業したり、 OS /ドライバー、またはいずれにしてもc#を使用していません。

于 2009-09-21T19:12:54.953 に答える
3

HLVMプロジェクトのガベージ コレクターの stop-the-world フェーズにスピン ロックを使用しました。スピン ロックは簡単でおもちゃの VM だからです。ただし、スピンロックはそのコンテキストでは逆効果になる可能性があります。

Glasgow Haskell Compiler のガベージ コレクタのパフォーマンス バグの 1 つは非常に煩わしいため、「最後のコアのスローダウン」という名前が付けられています。これは、GC でのスピンロックの不適切な使用の直接的な結果であり、Linux ではそのスケジューラーが原因で悪化しますが、実際には、他のプログラムが CPU 時間を競合している場合は常にその影響が観察されます。

この効果はここの 2 番目のグラフで明らかであり、Haskell プログラムがわずか 5 コアを超えてパフォーマンスの低下を確認している最後のコア以外にも影響を与えていることがわかります。

于 2010-06-11T23:53:34.293 に答える