LMAXのDiruptorはどのように働きますか?(stackoverflowの回答)
3584 ワード
原文のアドレスhttp://stackoverflow.com/questions/6559308/how-does-lmaxs-disruptor-pattern-work
最初の答え Jul 3'11 at 8:03 マイケル・バーカー):
Displaptorの最も簡単な説明はスレッド間通信の最も効率的な方法である。それは行列の代わりに利用できます。SEDAとActorsモードの特性がたくさんあります。キューと比較します。他のスレッドにメッセージを送信し、必要な時に他のスレッドを起動します。しかし、彼らの間には三つの大きな違いがあります。1.利用者は、Entryクラスを継承し、事前に割り当てを行う工場を提供することによって、メッセージの格納方法を定義する。このようにメモリを繰り返し利用したり、実現されたEntryは他のオブジェクトの参照を持つことができます。2.メッセージをDiruptorに入れるには、2つのステップが必要です。まず、ring bufferの中で名声があるインターフェースで、このインターフェースは使用者に正しいデータを保存できるEntryを提供します。そして、このイベントを提出しなければなりません。上記のようにメモリを活用するためには、この2つのステップが必要です。送信動作は、消費者スレッドがメッセージを読むことができるようにする。3.ring bufferで消費されたメッセージは消費者が追跡するべきです。ring bufferにメッセージを追跡させないことは、各スレッドが自分でカウンタを維持しているため、書き込み衝突の発生を減らすことができる。Actorsと比較したActorモデルは、Diruptorに最も近いプログラムモデルで、特にBatConsmer/Batch Handler類を使用しています。これらのクラスは、消費されたシリアル番号を維持するすべての複雑な実装を隠しており、重要な出来事が発生した時に簡単なコールバック方法を提供します。しかし、二つの小さな違いがあります。1.Diruptorはスレッドを使って消費者のモデルに対応していますが、Actorsはマルチペアのモデルを使っています。例えば、できるだけ多くのactorを持つことができます。それらは一定の数のスレッドに分布します。2.Batch Handlerインターフェースは、I/O操作をバッチ処理に一括して実行してスループットを向上させる追加的な(しかも重要な)フィードバック方法を提供しています。他のActorフレームを使ってもバッチ処理ができますが、バッチ処理の実行が終了したコールバック方法はほとんどありません。タイムアウトを使ってバッチ処理が終了したかどうかを判断するしかありません。SEDAと比較してLMAXを設計しました。DispruptorモードはSEDAに代わるためです。1.SEDAと比べて、disruptorの主な改善は並行して仕事ができることです。Displaptorはマルチキャストメッセージをサポートしてこの機能を実現し、同じメッセージ(一致する順序で)が複数の消費者に送信される。このようにして、パイプの中での交差を避けることができます。2.消費者は他の消費者の処理結果に頼ることができ、行列化した層をそれらの間に置くことによって。消費者は自分が依存している消費者のシリアルナンバーを簡単に見ることができます。このようにして、配管内の層の結合を避けることができます。メモリ障害と比較して,dispruptorを構造的,秩序的なメモリ障害として理解できる。その中で生産者障害は書く障害に相当し、消費者障害は読む障害に相当します。
二つ目の答え Jul 16'11 at 5:48 irreputtable):
まず、それが提供するプログラミングモデルを理解します。それは一つ以上の作者と読者がいます。古いものから新しいもの(左から右へ)の列があります。右側に項目を追加できます。各読者は左から右へ順番に項目を読みます。読者は明らかに作者を飛ばして先に読むことができません。項目は削除できません。「消費者」の代わりに「読者」を使って、項目が消費されると思われないようにします。最後の読者の左の項目は役に立たないと知っています。通常読者は同時に独立して項目を読み込むことができます。しかし、読者間の依存関係を宣言することができます。読者の間には任意の非環状依存があり得る。読者Bが読者Aに依存する場合、読者Bは、読者Aをスキップして先に読むことができない。読者Aは一つの項目を注釈することができますが、読者Bはこの注釈に依存していますので、読者間の依存があります。例えば、Aはある項目でいくつかの計算を行い、結果を項目のaフィールドに保存します。その後Aに進み、Bはこのエントリとエントリのaを読み取ることができる。読者CがAに依存していない場合、Cはaを読むべきではない。これは確かに面白いプログラミングモデルです。性能のいかんによらず,このモデルだけで応用に有利である。もちろん、LMAXの主な目標は性能です。Displaptorはあらかじめ割り当てられたエントリループを使用します。このリングは十分大きいですが、容量を超えないように上限があります。ループがいっぱいになったら、作者は一番遅い作者が前に進んで空間を作るまでずっと待っています。エントリオブジェクトは事前割り当てであり、GCの消費を低減するために常に存在します。私たちは新しい項目のオブジェクトを追加したり、古いものを削除したりしません。反対に、著者らは既存の項目を要求して、フィールドを塗りつぶして、読者に通知します。この二つのステップは本当に簡単な原子操作である。
最初の答え Jul 3'11 at 8:03 マイケル・バーカー):
Displaptorの最も簡単な説明はスレッド間通信の最も効率的な方法である。それは行列の代わりに利用できます。SEDAとActorsモードの特性がたくさんあります。キューと比較します。他のスレッドにメッセージを送信し、必要な時に他のスレッドを起動します。しかし、彼らの間には三つの大きな違いがあります。1.利用者は、Entryクラスを継承し、事前に割り当てを行う工場を提供することによって、メッセージの格納方法を定義する。このようにメモリを繰り返し利用したり、実現されたEntryは他のオブジェクトの参照を持つことができます。2.メッセージをDiruptorに入れるには、2つのステップが必要です。まず、ring bufferの中で名声があるインターフェースで、このインターフェースは使用者に正しいデータを保存できるEntryを提供します。そして、このイベントを提出しなければなりません。上記のようにメモリを活用するためには、この2つのステップが必要です。送信動作は、消費者スレッドがメッセージを読むことができるようにする。3.ring bufferで消費されたメッセージは消費者が追跡するべきです。ring bufferにメッセージを追跡させないことは、各スレッドが自分でカウンタを維持しているため、書き込み衝突の発生を減らすことができる。Actorsと比較したActorモデルは、Diruptorに最も近いプログラムモデルで、特にBatConsmer/Batch Handler類を使用しています。これらのクラスは、消費されたシリアル番号を維持するすべての複雑な実装を隠しており、重要な出来事が発生した時に簡単なコールバック方法を提供します。しかし、二つの小さな違いがあります。1.Diruptorはスレッドを使って消費者のモデルに対応していますが、Actorsはマルチペアのモデルを使っています。例えば、できるだけ多くのactorを持つことができます。それらは一定の数のスレッドに分布します。2.Batch Handlerインターフェースは、I/O操作をバッチ処理に一括して実行してスループットを向上させる追加的な(しかも重要な)フィードバック方法を提供しています。他のActorフレームを使ってもバッチ処理ができますが、バッチ処理の実行が終了したコールバック方法はほとんどありません。タイムアウトを使ってバッチ処理が終了したかどうかを判断するしかありません。SEDAと比較してLMAXを設計しました。DispruptorモードはSEDAに代わるためです。1.SEDAと比べて、disruptorの主な改善は並行して仕事ができることです。Displaptorはマルチキャストメッセージをサポートしてこの機能を実現し、同じメッセージ(一致する順序で)が複数の消費者に送信される。このようにして、パイプの中での交差を避けることができます。2.消費者は他の消費者の処理結果に頼ることができ、行列化した層をそれらの間に置くことによって。消費者は自分が依存している消費者のシリアルナンバーを簡単に見ることができます。このようにして、配管内の層の結合を避けることができます。メモリ障害と比較して,dispruptorを構造的,秩序的なメモリ障害として理解できる。その中で生産者障害は書く障害に相当し、消費者障害は読む障害に相当します。
二つ目の答え Jul 16'11 at 5:48 irreputtable):
まず、それが提供するプログラミングモデルを理解します。それは一つ以上の作者と読者がいます。古いものから新しいもの(左から右へ)の列があります。右側に項目を追加できます。各読者は左から右へ順番に項目を読みます。読者は明らかに作者を飛ばして先に読むことができません。項目は削除できません。「消費者」の代わりに「読者」を使って、項目が消費されると思われないようにします。最後の読者の左の項目は役に立たないと知っています。通常読者は同時に独立して項目を読み込むことができます。しかし、読者間の依存関係を宣言することができます。読者の間には任意の非環状依存があり得る。読者Bが読者Aに依存する場合、読者Bは、読者Aをスキップして先に読むことができない。読者Aは一つの項目を注釈することができますが、読者Bはこの注釈に依存していますので、読者間の依存があります。例えば、Aはある項目でいくつかの計算を行い、結果を項目のaフィールドに保存します。その後Aに進み、Bはこのエントリとエントリのaを読み取ることができる。読者CがAに依存していない場合、Cはaを読むべきではない。これは確かに面白いプログラミングモデルです。性能のいかんによらず,このモデルだけで応用に有利である。もちろん、LMAXの主な目標は性能です。Displaptorはあらかじめ割り当てられたエントリループを使用します。このリングは十分大きいですが、容量を超えないように上限があります。ループがいっぱいになったら、作者は一番遅い作者が前に進んで空間を作るまでずっと待っています。エントリオブジェクトは事前割り当てであり、GCの消費を低減するために常に存在します。私たちは新しい項目のオブジェクトを追加したり、古いものを削除したりしません。反対に、著者らは既存の項目を要求して、フィールドを塗りつぶして、読者に通知します。この二つのステップは本当に簡単な原子操作である。
setNewEntry(EntryPopulator);
interface EntryPopulator{ void populate(Entry existingEntry); }
プリキャストのエントリは、adjacent memorycelsのアドホック・エンタテインメント割り当てに相当し、読者が順番にエントリを読み込むので、CPUキャッシュを利用することが重要です。ロック、CAS、さらにメモリ障害を避けるために多くの努力をしました。例えば、作者一人だけなら不変のシリアル変数を使います。開発者への書き込み:異なる読者は、競合を避けるために、エントリ内の異なるフィールドに書くべきです。(事実上、彼らは別のキャッシュ行に書くべきです。)ある特定の注釈の読者は、依存しない読者が読むことができるものに触れてはいけません。