web-dev-qa-db-ja.com

スキップリストとバイナリ検索ツリー

最近、 スキップリスト として知られるデータ構造に出会いました。バイナリ検索ツリーと非常によく似た動作をしているようです。

なぜバイナリ検索ツリーでスキップリストを使用したいのですか?

207
Claudiu

スキップリストは、同時アクセス/変更に適しています。 Herb Sutterは、並行環境でのデータ構造について 記事 を書きました。より詳細な情報があります。

最も頻繁に使用されるバイナリ検索ツリーの実装は、 赤黒木 です。同時に問題が発生するのは、ツリーを修正するときに、しばしば再バランスが必要になるからです。リバランス操作は、ツリーの大部分に影響を与える可能性があり、多くのツリーノードでミューテックスロックが必要になります。スキップリストへのノードの挿入ははるかにローカライズされており、影響を受けるノードに直接リンクされているノードのみをロックする必要があります。


Jon Harropsコメントからの更新

フレイザーとハリスの最新の論文を読みます ロックのない並行プログラミング 。ロックフリーのデータ構造に興味があるなら、本当に良いものです。このペーパーでは、 トランザクションメモリ と理論的操作であるマルチワード比較およびスワップMCASに焦点を当てています。どちらのハードウェアもまだサポートしていないため、これらは両方ともソフトウェアでシミュレートされます。私は彼らがソフトウェアでMCASを構築できたことにかなり感銘を受けました。

ガベージコレクターが必要なため、トランザクションメモリは特に説得力がありませんでした。また、 ソフトウェアトランザクションメモリ はパフォーマンスの問題に悩まされています。ただし、ハードウェアトランザクションメモリが一般的になれば、とても嬉しいです。最終的にはまだ研究中であり、今後10年ほどは製品コードに使用できません。

セクション8.2では、複数の同時ツリー実装のパフォーマンスを比較しています。それらの調査結果を要約します。 50、53、および54ページにいくつかの非常に有益なグラフがあるので、pdfをダウンロードする価値があります。

  • ロックスキップリストは非常に高速です。同時アクセスの数に応じて、非常に優れた拡張性を発揮します。これがスキップリストを特別なものにし、他のロックベースのデータ構造がプレッシャーの下でひそむ傾向があります。
  • ロックフリースキップリストは、スキップリストのロックより一貫して高速ですが、ほとんどありません。
  • トランザクションスキップリストは、ロックバージョンおよび非ロックバージョンよりも一貫して2〜3倍遅いです。
  • 赤黒木をロックする同時アクセス下で鳴きます。それらのパフォーマンスは、新しい同時ユーザーごとに直線的に低下します。 2つの既知のロック赤黒ツリー実装のうち、1つは本質的にツリーリバランス中にグローバルロックを持ちます。もう1つは派手な(そして複雑な)ロックのエスカレーションを使用しますが、それでもグローバルロックバージョンを大幅に実行しません。
  • ロックフリーの赤黒木は存在しません(もはや真実ではありません。更新を参照してください)。
  • トランザクションの赤黒木は、トランザクションのスキップリストと同等です。それは非常に驚くべきことであり、非常に有望でした。トランザクションメモリ。書き込みははるかに簡単ですが、速度は遅くなります。クイック検索と同じくらい簡単で、非並行バージョンで置き換えることができます。

更新
ロックフリーツリーに関するペーパー: CASを使用したロックフリー赤黒ツリー
詳しく調べていませんが、表面上はしっかりしているようです。

239
deft_code

まず、ランダム化されたデータ構造と最悪の場合の保証を提供するデータ構造を公平に比較​​することはできません。

スキップリストは、ディーンアンドジョーンズの詳細について説明されている方法で、ランダムにバランスの取れたバイナリ検索ツリー(RBST)と同等です "スキップリストとバイナリ検索ツリーの双対性の調査"

逆に、最悪の場合のパフォーマンスを保証する確定的なスキップリストを使用することもできます。 Munro et al。

上記のいくつかの主張とは反対に、並行プログラミングでうまく機能するバイナリ検索ツリー(BST)の実装を使用できます。並行性に焦点を当てたBSTの潜在的な問題は、赤黒(RB)ツリーの場合と同じように、バランシングに関して保証されていた保証を簡単に取得できないことです。 (ただし、「標準」、つまりrandomzided、スキップリストでもこれらの保証は得られません。)常にバランスを維持することと、良好な(およびプログラムしやすい)同時アクセスとの間にはトレードオフがあります。したがってrelaxedRBツリーは通常、良好な並行性が必要な場合に使用されます。リラクゼーションは、すぐにツリーのバランスを取り直さないことにあります。多少古くなった(1998年の)調査については、Hankeの `` The Performance of Concurrent Red-Black Tree Algorithms '' [ps.gz] を参照してください。

これらの最近の改善の1つは、いわゆるクロマティックツリーです(基本的に、黒が1で赤がゼロになるような重みがあります) 、ただし、間に値を許可することもできます)。また、クロマティックツリーはスキップリストに対してどのように機能しますか?ブラウンらが何を見ようか。 「非ブロッキングツリーの一般的なテクニック」 (2014)は次のように言わなければなりません。

128個のスレッドで、私たちのアルゴリズムはJavaのノンブロッキングスキップリストよりも13%から156%優れています。これは、ブロンソンらのロックベースのAVLツリーです。 63%から224%、およびソフトウェアトランザクションメモリ(STM)を使用するRBTは13から134倍

追加する編集:Pughのロックベースのスキップリスト。Fraserand Harris(2007)でベンチマークされました "Concurrent Programming Without Lock" 独自のロックフリーバージョンに近づいている(十分に主張されているポイント)ここの一番上の答えで)、良好な同時操作のために調整されています。 Pughの 「スキップリストの同時メンテナンス」 。ただし、穏やかな方法です。それにもかかわらず、新しい/ 2009年の論文 「単純な楽観的スキップリストアルゴリズム」 Herlihyらによる、同時スキップリストのおそらくよりシンプルな(Pughの)ロックベースの実装を提案し、Pughはそうではないと批判した彼らに十分な説得力のある正当性の証拠を提供する。この(恐らくあまりにも退屈な)辱を捨てて、Herlihy et al。スキップリストのより単純なロックベースの実装は、JDKのロックフリー実装と同様に実際にはスケーリングに失敗しますが、高い競合(50%の挿入、50%の削除、0%のルックアップ)のみを示します。ハリスはまったくテストしませんでした。 FraserとHarrisは、75%のルックアップ、12.5%の挿入、12.5%の削除のみをテストしました(〜500K要素のスキップリストで)。 Herlihyらのより単純な実装。また、テストした競合が少ない場合(70%のルックアップ、20%の挿入、10%の削除)、JDKのロックフリーソリューションに近づきます。スキップリストを十分に大きくした場合、つまり、ロックの競合の可能性が無視できるようになったときに、このシナリオのロックフリーソリューションを実際に破りました。 Herlihy et al。 Pughの証明に対するハングアップを乗り越え、彼の実装もテストしていましたが、残念ながらそうはしませんでした。

EDIT2:すべてのベンチマークのマザーロード(2015年公開)を見つけました:Gramoliの 「同期について知りたい以上のこと。同期、同時アルゴリズムへの同期の影響の測定」 :以下は抜粋ですこの質問に関連する画像。

enter image description here

「Algo.4」は、上記のBrown等の前身(2011年以前のバージョン)です。 (2014年版がどれだけ良くも悪くもわからない)。 「Algo.26」は上記のHerlihyのものです。ご覧のとおり、更新時にゴミになります。また、ここで使用されているIntel CPUの方が、元の論文のSun CPUよりもずっと悪いです。 「Algo.28」は、JDKのConcurrentSkipListMapです。他のCASベースのスキップリストの実装と比較して、期待したほどうまくいきません。競合が激しい場合の勝者は、Crain et al。によって記述されたロックベースのアルゴリズムである「Algo.2」です(!!)。 "競合に優しいバイナリ検索ツリー" および "Algo.30"は "マルチコアの対数データ構造" からの「回転スキップリスト」です。 「Algo.29」は 「ホットスポット非ブロッキングスキップリストなし」 です。 Gramoliは、これら3つの勝者アルゴリズム論文すべての共著者であることに注意してください。 「Algo.27」は、FraserのスキップリストのC++実装です。

Gramoliの結論は、CASベースの並行ツリー実装を台無しにする方が、同様のスキップリストを台無しにするよりもはるかに簡単だということです。そして、数字に基づいて、それは異論を唱えるのは難しいです。この事実についての彼の説明は次のとおりです。

ロックフリーのツリーを設計することの難しさは、複数の参照をアトミックに変更することの難しさに起因しています。スキップリストは、後続のポインタを介して互いにリンクされたタワーで構成され、各ノードはその直下のノードを指します。各ノードは後継タワーとその下に後継者を持っているため、ツリーによく似ていると考えられますが、大きな違いは、下向きポインタが一般に不変であり、ノードのアトミックな変更を単純化することです。この違いは、おそらく、図[上記]で見られるように、スキップリストが激しい競合の下でツリーよりも優れている理由です。

この困難を克服することは、Brownらの最近の研究における重要な関心事でした。彼らは完全に別個の(2013)論文を持っています 「非ブロック化データ構造のための実用的なプリミティブ」 LLX/SCXと呼ばれるマルチレコードLL/SC複合「プリミティブ」の構築についてマシンレベル)CAS。ブラウン等。このLLX/SCXビルディングブロックを2014年(ただし2011年ではない)の同時ツリー実装で使用しました。

ここで "ホットスポットなし" /コンテンションフレンドリー(CF)スキップリスト の基本的な考え方を要約する価値があると思います。これは、リラックスしたRBツリー(および同様の一致性のデータ構造)からの本質的なアイデアを追加します。タワーは、挿入後すぐには構築されず、競合が少なくなるまで遅延されます。逆に、高い塔を削除すると、多くの競合が発生する可能性があります。これは、1990年のPughの同時スキップリストペーパーまで遡って観察されたため、Pughが削除に関するポインターの反転を導入したのです(スキップリストに関するWikipediaのページでは、今日でも言及されていません)。 CFスキップリストはこれをさらに一歩進め、高い塔の上のレベルの削除を遅らせます。 CFスキップリストでの両方の種類の遅延操作は、(CASベースの)別のガベージコレクターのようなスレッドによって実行され、その作成者は「適応スレッド」と呼びます。

Synchrobenchコード(テストされたすべてのアルゴリズムを含む)は、 https://github.com/gramoli/synchrobench で入手できます。最新のブラウン等。実装(上記には含まれていません)は http://www.cs.toronto.edu/~tabrown/chromatic/ConcurrentChromaticTreeMap.Java で入手できます。32+コアマシンを利用できる人はいますか? J/K私のポイントは、これらを自分で実行できるということです。

75
Fizz

また、与えられた答えに加えて(実装の容易さと、バランスの取れたツリーに匹敵するパフォーマンスとの組み合わせ)。スキップリストには、その実装内にリンクリストが効果的に含まれているため、順方向のトラバース(前方および後方)の実装がはるかに簡単であることがわかりました。

12
Evan Teran

実際には、プロジェクトのBツリーのパフォーマンスがスキップリストよりも優れていることがわかりました。スキップリストは理解しやすいようですが、Bツリーの実装はthatハードではありません。

私が知っている1つの利点は、一部の賢明な人々が、アトミック操作のみを使用するロックフリーの同時スキップリストを実装する方法を考え出したことです。たとえば、Java 6にはConcurrentSkipListMapクラスが含まれており、クレイジーな場合はソースコードを読むことができます。

しかし、並行Bツリーバリアントを記述するのもそれほど難しくありません-他の誰かがそれを行ったのを見ました-ツリーを下るときに「念のために」ノードをプリエンプティブに分割およびマージする場合、必要はありませんデッドロックを心配し、一度にツリーの2つのレベルでロックを保持する必要があるだけです。同期のオーバーヘッドは少し高くなりますが、Bツリーはおそらくより高速です。

9
Jonathan

Wikipedia 引用した記事から:

Θ(n)操作は、昇順ですべてのノードを訪問することを強制します(リスト全体を印刷するなど)。最適な方法でスキップリストのレベル構造の舞台裏でのランダム化を実行する機会を提供します。スキップリストをO(log n)の検索時間にする。 [...]スキップリスト、最近実行されていない[そのような]Θ(n)操作、は、従来のバランスのとれた絶対的な最悪の場合のパフォーマンス保証を提供しません。ツリーデータ構造。スキップリストの作成に使用されるコインフリップがバランスの悪い構造を生成する可能性が非常に低いためです。

編集:だからトレードオフです:スキップリストは、不均衡なツリーに縮退するリスクがあるので、使用するメモリが少なくなります。

8
Mitch Wheat

スキップリストはリストを使用して実装されます。

一重および二重にリンクされたリストにはロックフリーソリューションが存在しますが、O(logn)データ構造にCASのみを直接使用するロックフリーソリューションはありません。

ただし、CASベースのリストを使用してスキップリストを作成できます。

(CASを使用して作成されるMCASは、任意のデータ構造を許可し、MCASを使用して概念実証の赤黒ツリーが作成されていることに注意してください)。

だから、奇妙なことに、彼らは非常に有用であることが判明しました:-)

2
Blank Xavier