web-dev-qa-db-ja.com

ロックフリーアルゴリズムは、ロックフルアルゴリズムよりも実際に優れたパフォーマンスを発揮しますか?

レイモンドチェン やっています 巨大シリーズオンロックフリーアルゴリズムInterlockedXxx関数の単純なケースを超えて、これらすべての一般的なパターンは、それらが独自のロックを実装することであるように思われます。確かに、プロセッサロックはありませんが、一貫性を確保するために各CPUで何度もループするという概念は、スピンロックに非常によく似ています。また、スピンロックであるため、他のスレッドを待機している間はクォンタムを制御できないため、オペレーティングシステムに付属している一般的なロックよりも効率が低下します。したがって、誰かが私のところに来て「しかし私のアルゴリズムはロックフリーです」と言うときはいつでも、私の一般的な応答は「そう」ですか?

私は興味があります-ロックフリーのアルゴリズムがロックフルの対応物よりもエッジを持っていることを示すベンチマークが利用可能ですか?

46
Billy ONeal

一般に、ロックフリーアルゴリズムはスレッドごとの効率が低くなります。前述のように、単純なロックよりもロックフリーアルゴリズムを実装するために多くの作業を行っています。

ただし、競合に直面しても、アルゴリズム全体の全体的なスループットが劇的に向上する傾向があります。 スレッド切り替えの待ち時間 および コンテキストスイッチ 、これは高速で、多くのスレッドでアプリケーションのスループットを大幅に低下させます。ロックフリーアルゴリズムは、効果的に独自の「ロック」を実装していますが、コンテキストスイッチの数を防止または削減する方法で実装しているため、対応するロックを実行する傾向があります。

そうは言っても、これのほとんどは問題のアルゴリズム(および実装)に依存します。たとえば、以前のロックメカニズムを使用する代わりに、.NET 4の新しい同時コレクションに切り替えることができたルーチンがいくつかあり、アルゴリズムの合計速度が30%近く向上したことが測定されています。そうは言っても、基本的なロックと比較した場合、これらの同じコレクションのいくつかを使用するとパフォーマンスが低下することを示す多くのベンチマークがあります。すべてのパフォーマンスの最適化と同様に、measureになるまで本当にわかりません。

27
Reed Copsey

InterlockedXxx関数の単純なケースを超えて、これらすべての一般的なパターンは、独自のロックを実装しているようです。

ここでの答えはどれも、「ロックフリー」 [〜#〜] cas [〜#〜] ループとミューテックスまたはスピンロックの違いの核心に達するようには見えません。

重要な違いは、lock-freeアルゴリズムは、それ自体で進歩することが保証されていることです-他のスレッドの支援なし。ロックまたはスピンロックを使用すると、ロックを取得できない貧弱なスレッドは、ロックを所有するスレッドに翻弄されて完全になります。ロックを取得できない貧弱なスレッドは、wait(ビジー待機またはOS支援スリープのいずれかを介して)以外は何もできません。

CASでループするロックフリーアルゴリズムを使用すると、他の競合するスレッドが何をしているかに関係なく、各スレッドが進行することが保証されます。各スレッドは、基本的に、独自の運命を制御しています。はい、それでも何度もループする必要があるかもしれませんが、ループする回数は競合するスレッドの数によって制限されます。ほとんどの場合、無限にループすることはできません。 (実際には、たとえば LL/SC ループが原因でライブロックが発生する可能性があります)-しかし、これに対処するためにスレッド自体が対策を講じることができます-ロックを保持している別のスレッドに翻弄されることはありません。

性能は状況によります。私は、ロックフリーアルゴリズムの目覚ましい例が、スレッドの競合が多い場合でも、対応するロックよりも完全に優れていることを確認しました。 Debian 7を実行しているx86-64マシンで、C++ Boost.Lockfreeキュー(Michael/Scottアルゴリズムに基づく)と、std::queueで囲まれた古いstd::mutexのパフォーマンスを比較しました。スレッドの競合が多い場合、ロックフリーバージョンはほぼ2倍遅くなりました。

それで、それはなぜですか?さて、ロックフリーアルゴリズムのパフォーマンスは、最終的には実装の詳細に帰着します。アルゴリズムはどのようにABAを回避しますか?安全なメモリ再生をどのように実現しますか?非常に多くのバリエーションがあります...タグ付きポインター、エポックベースのレクラメーション、RCU /静止状態、ハザードポインター、一般的なプロセス全体のガベージコレクションなど。これらの戦略はすべてパフォーマンスに影響を及ぼし、アプリケーション全般に​​制限を課すものもあります設計することができます。私の経験では、一般に、参照カウントアプローチ(またはタグ付きポインターアプローチ)はパフォーマンスが低下する傾向があります。ただし、代替手段の実装ははるかに複雑になる可能性があり、スレッドローカルストレージまたは一般化されたガベージコレクションに基づいた、より多くのメモリ再利用インフラストラクチャが必要になります。

17
Charles Salvia

ロックフリーは必ずしも高速であるとは限りませんが、デッドロックやライブロックの可能性を排除できるため、プログラムが常に終了に向けて進行することを保証できます。ロックを使用すると、そのような保証を行うことは困難です。デッドロックが発生する可能性のある実行シーケンスを見逃しがちです。

それを過ぎて、それはすべて依存します。少なくとも私の経験では、速度の違いは、ロックを使用するかどうかよりも、実装で展開されるスキルレベルに依存する傾向があります。

11
Jerry Coffin

X64上のWindowsでは、単純な(フリーリストの前に結合配列がない)ロックフリーフリーリストは、ミューテックスベースのフリーリストよりも約1桁高速です。

私のラップトップ(Core i5)では、シングルスレッドのロックフリーの場合、1秒あたり約3,100万回のフリーリスト操作が可能ですが、ミューテックスの場合は1秒あたり約230万回の操作が可能です。

2つのスレッド(別々の物理コア上)の場合、ロックフリーでは、スレッドごとに約1,240万のフリーリスト操作が実行されます。ミューテックスを使用すると、1秒あたり約80 [〜#〜] 1000 [〜#〜] 1回の操作が可能になります。

5
user82238

ロックフリーアルゴリズムは、ブロックするアルゴリズムよりも絶対に高速です。しかしもちろん、その逆も当てはまります。実装のパフォーマンスがロッキングカウンターパートよりも優れていると仮定すると、唯一の制限要因は競合です。

2つのJavaクラス、ConcurrentLinkedQueueとLinkedBlockingQueueを使用します。中程度の実世界の競合では、CLQはLBQよりもかなり優れています。競合が激しい場合は、中断スレッドを使用すると、LBQのパフォーマンスが向上します。

User237815に同意しません。同期されたキーワードは、以前ほど多くのオーバーヘッドを必要としませんが、ロックフリーアルゴリズムと比較して、単一のCASと比較してかなりのオーバーヘッドが関連付けられています。

1
John Vint

真にロックフリーのアルゴリズムの主な利点は、タスクが失敗した場合でも堅牢であるということです(ロックフリーは「ロックを使用しない」(*)よりも厳しい条件であることに注意してください)。不要なロックを回避することにはパフォーマンス上の利点がありますが、最もパフォーマンスの高いデータ構造は、多くの場合、ロックを操作できるものですが、スラッシングを最小限に抑えるためにロックを使用できます。

(*)「ロックフリー」のマルチプロデューサーキューで、間違ったタイミングでウェイレイドされたプロデューサーが、作業が完了するまで消費者が新しいアイテムを見ることができないという試みをいくつか見ました。このようなデータ構造は、実際には「ロックフリー」と呼ばれるべきではありません。ブロックされた1つのプロデューサーは、他のプロデューサーの進行をブロックしませんが、任意にコンシューマーをブロックする可能性があります。

1
supercat

Javaでは、少なくとも、ロック自体は非常に高速です。同期されたキーワードは、多くのオーバーヘッドを追加しません。ループ内で同期メソッドを呼び出すだけで、自分でベンチマークを行うことができます。

ロックは競合がある場合にのみ遅くなり、ロックされるプロセスは瞬時ではありません。

0
ccleve

最近 JavaOne Russia Oracleの従業員(Javaパフォーマンスとベンチマーク)を専門とする)は、CAS(実際にはロックフリーの高レベルスピンロック)とクラシックロック(Java.util.concurrent.locks.ReentrantLock)

http://dl.dropbox.com/u/19116634/pics/lock-free-vs-locks.png //申し訳ありませんが、画像を貼り付けることができません

これによると、スピンロックは、少数のスレッドがモニターにアクセスしようとするまで、パフォーマンスが向上します。

0
leventov

ロックフリーには、スリープしないという利点もあります。カーネルには、スリープが許可されていない場所があります(Windowsカーネルにはそれらがたくさんあります)。これにより、データ構造を使用する機能が制限されます。

0
user82238

はい、ロックの自由は進歩を保証しますが、一部のプラットフォームで可能なスレッドを手動で中止するか、クリティカルセクションに割り当ててメモリ不足の例外を取得しない限り、またはそのような愚かなことは必要ありません。適切に実装されたスピンロックは、通常、初めてまたは失敗した試行の後に多くの作業を行うため、同等に実行されない場合、ほとんどの場合、ロックレスアプローチよりも優れています。スピン時間を短くし、CPUを比較交換命令で圧倒したり、他のスレッドにスレッドタイムスライスを与えて(これにより、スケジュール外のスレッドがウェイクアップしてロックを解放する機会が与えられた後)元に戻らない場合は、ロックフリーコードのパフォーマンスが向上します。それ以外は可能だとは思いません。私は興味がなく、スピンロックが適合しない複雑なデータ型にも興味がありませんでしたが、それでも適切に設計されたロックベースのアルゴリズムの方が常に優れていると感じています。私は間違っているかもしれません。

0
TakeMeAsAGuest