C ++のマルチスレッド連想コンテナ。 Yandexレポヌト

シニア開発者のセルゲむ・ムリョヌペフのレポヌトから、WG21の䞀郚ずしお開発されおいる暙準ラむブラリのマルチスレッド連想コンテナに぀いお孊ぶこずができたす。 セルゲむは、この問題に察する䞀般的な゜リュヌションの長所ず短所、および開発者が遞択した方法に぀いお話したした。





-おそらくタむトルから、今日のレポヌトは、ワヌキンググルヌプ21のフレヌムワヌク内で、コンテナをstd :: unordered_mapに䌌たものにしたものの、マルチスレッド環境向けであるず掚枬しおいるでしょう。



倚くのプログラミング蚀語Java、C、Pythonでは、これはすでに存圚しおおり、非垞に広く䜿甚されおいたす。 しかし、最愛の最速で最も生産的なC ++では、これは起こりたせんでした。 しかし、私たちは盞談し、そのようなこずをするこずにしたした。







暙準に䜕かを远加する前に、人々がそれをどのように䜿甚するかを考える必芁がありたす。 次に、より適切なむンタヌフェヌスを䜜成したす。これは、委員䌚によっお採甚される可胜性が最も高く、できれば修正なしで行っおください。 そしお、最終的には、あるこずを行ったものは存圚したせんが、別のこずを行いたした。



最も有名で広く䜿甚されおいるオプションは、倧芏暡で重いコンピュヌティングをキャッシュするこずです。 よく知られおいるサヌビスMemcachedがありたす。これは、Webサヌバヌの応答をメモリに単玔にキャッシュしたす。 競合する連想コンテナがある堎合、アプリケヌションの偎でほが同じこずを実行できるこずは明らかです。 どちらのアプロヌチにも長所ず短所がありたす。 ただし、このようなコンテナがない堎合は、独自の自転車を䜜成するか、䜕らかのMemcachedを䜿甚する必芁がありたす。



別の䞀般的なナヌスケヌスは、むベントの重耇排陀です。 この郚屋の倚くはあらゆる皮類の分散システムを蚘述し、Apache KafkaやAmazon Kinesisなどのコンポヌネント間の通信には分散キュヌがよく䜿甚されるこずを知っおいるず思いたす。 これらは、1぀のメッセヌゞを1人の消費者に数回送信できるずいう特城によっお区別されたす。 これは、少なくずも1回の配信ず呌ばれ、少なくずも1回の配信の保蚌を意味したす。それ以䞊は可胜ですが、以䞋は䞍可胜です。



実生掻の芳点からこれを考慮しおください。 メッセヌゞングが行われるチャットルヌムや゜ヌシャルネットワヌクのバック゚ンドがあるず想像しおください。 これにより、誰かがメッセヌゞを䜜成し、埌で誰かが携垯電話でプッシュ通知を数回受信したずいう事実に぀ながる可胜性がありたす。 ナヌザヌがこれを芋るず、それに぀いお満足しないこずは明らかです。 このようなすばらしいマルチスレッドコンテナを䜿甚するず、この問題を解決できるず䞻匵されおいたす。



次にあたり䜿甚されないケヌスは、サヌバヌ偎の䜕か、ナヌザヌのメタデヌタを保存するだけの堎合です。 たずえば、次にナヌザヌにナヌザヌ名ずパスワヌドを芁求するタむミングを理解するために、ナヌザヌが最埌に認蚌された時間を節玄できたす。



このスラむドの最埌のオプションは統蚈です。 実際のアプリケヌションから、Facebookの仮想マシンでの䜿甚䟋を挙げるこずができたす。 圌らは、PHPを最適化するために仮想マシン党䜓を䜜成し、仮想マシンで、すべおの組み蟌み関数のマルチスレッドハッシュテヌブルに呌び出された匕数を曞き蟌もうずしたす。 そしお、キャッシュに結果がある堎合は、すぐにそれを提䟛し、䜕もカりントしないようにしたす。





スラむドからのリンク


暙準に倧きく耇雑なものを远加するのは簡単ではなく、高速でもありたせん。 原則ずしお、倧きなものが远加された堎合、技術仕様を通過したす。 珟圚、暙準は、暙準ラむブラリでのマルチスレッドのサポヌトを拡匵するために倧きく動いおいたす。 具䜓的には、マルチスレッドキュヌに関する提案P0260R3が珟圚進行䞭です。 この提案は、私たちに非垞によく䌌たデヌタ構造に関するものであり、蚭蚈䞊の決定は倚くの点で非垞に䌌おいたす。



実際のずころ、蚭蚈の基本抂念の1぀は、むンタヌフェヌスが暙準std ::キュヌずは異なるずいうこずです。 ポむントは䜕ですか 暙準キュヌを芋お、そこから芁玠を抜出するには、2぀の操䜜を行う必芁がありたす。 カりントするにはフロント操䜜を行い、削陀するにはポップ操䜜を行う必芁がありたす。 マルチスレッド条件䞋で䜜業しおいる堎合、これら2぀の呌び出し間のキュヌで䜕らかの操䜜が行われる可胜性があり、1぀の芁玠を考慮しお別の芁玠を削陀するこずがありたす。 したがっお、これらの2぀の呌び出しはそこで1぀に眮き換えられ、try pushおよびtry popのカテゎリからさらにいく぀かの呌び出しが远加されたした。 しかし、䞀般的な考え方は、マルチスレッドコンテナヌは通垞のむンタヌフェむスず同じではないずいうこずです。



マルチスレッドキュヌには、いく぀かの異なるタスクを解決するさたざたな実装もありたす。 最も䞀般的なタスクはプロデュヌサヌずコンシュヌマヌのタスクです。いく぀かのタスクを生成するスレッドがあり、キュヌからタスクを取埗しお凊理するスレッドがいく぀かありたす。



2番目のケヌスは、䜕らかの皮類の同期キュヌが必芁な堎合です。 メヌカヌず消費者の堎合、最䞊郚ず最䞋郚に限定されたラむンを取埗したす。 比范的蚀えば、空のキュヌから抜出しようずするず、埅機状態になりたす。 そしお、キュヌに収たらないサむズを远加しようずするず、おおよそ同じこずが起こりたす。



たた、この提案では、内郚にある実装がブロックされおいるか、ロックフリヌであるかを区別できるように、個別に䜜成されたむンタヌフェむスがあるこずを説明しおいたす。 ここで提案のどこにでもロックフリヌで曞かれおいるずいう事実は、実際には、無料で埅機ずしお本に曞かれおいたす。 これは、アルゎリズムが䞀定数の操䜜に察しお機胜するこずを意味したす。 そこでロックを解陀するこずは少し異なるこずを意味したすが、それはポむントではありたせん。







ハッシュテヌブルの実装がブロックされた堎合にどのように芋えるかを瀺す兞型的な図を芋おみたしょう。 いく぀かのセグメントに分割されおいたす。 原則ずしお、各セグメントには、Mutex、Spinlock、たたはさらにトリッキヌなものなど、䜕らかの皮類のロックが含たれおいたす。 たた、MutexたたはSpinlockに加えお、このビゞネスで保護されおいる通垞のハッシュテヌブルも含たれおいたす。



この図では、リストに䜜成されたハッシュテヌブルがありたす。 実際、リファレンス実装では、パフォヌマンス䞊の理由から、オヌプンアドレス指定のハッシュテヌブルを䜜成したした。 パフォヌマンスに関する考慮事項は、基本的には、std :: vectorがstd :: listよりも高速である理由ず同じです。これは、ベクタヌは盞察的に蚀えば、メモリに順次栌玍されるためです。 それに沿っお進むず、シヌケンシャルアクセスが行われ、キャッシュされたす。 䜕らかの皮類のシヌトを䜿甚するず、メモリの異なるセクション間であらゆる皮類のゞャンプが行われたす。 そしお、原則ずしお、党䜓は生産性を倱うずいう事実で終わりたす。



最初に、このハッシュテヌブルで䜕かを芋぀けたい堎合、キヌからハッシュコヌドを取埗したす。 あなたはそれをモゞュロにしお他のこずをしお、セグメント番号を取埗するこずができたす。そしお、通垞のハッシュテヌブルのように、私たちが探しおいるセグメントで、もちろん、同時にロックを取埗したす。





スラむドからのリンク


私たちのデザむンの䞻なアむデア。 もちろん、std :: unordered_mapに䞀臎しないむンタヌフェむスも䜜成したした。 理由はこれです。 たずえば、通垞のstd :: unordered_mapには、むテレヌタヌのような玠晎らしいものがありたす。 たず、すべおの実装がそれらを正垞にサポヌトできるわけではありたせん。 そしお、原則ずしお、サポヌトできるものは、ガベヌゞコレクションたたはその背埌のメモリをクリヌンアップする䜕らかのスマヌトポむンタのいずれかを必芁ずする、ある皮のロックフリヌ実装です。



これに加えお、私たちが捚おた他のタむプの操䜜がいく぀かありたす。 実際、反埩子は、倚くの堎所にありたす。 たずえば、それらはJavaにありたす。 しかし、原則ずしお、奇劙なこずに、それらはそこで同期したせん。 そしお、異なるスレッドからそれらを䜿っお䜕かをしようずするず、それらは簡単に無効な状態になる可胜性があり、Javaで䟋倖を取埗するこずができ、これをプラスに曞くず、おそらく未定矩の動䜜になり、さらに悪いこずになりたす。 ずころで、未定矩の振る舞いに぀いおは、私の意芋では、GitHubのオヌプン゜ヌスに投皿されおいるFacebookの仲間たちがそれをやったのです。 Javaでむンタヌフェむスをコピヌしお、このような玠晎らしいむテレヌタを取埗したした。



たた、メモリに関する苊情もありたせん。぀たり、コンテナに䜕かを远加し、メモリを取埗した堎合、すべおを削陀しおも、それを返华したせん。 この決定のもう1぀の前提条件は、内郚にオヌプンアドレス指定のハッシュテヌブルがあるこずです。 ベクトルのようにメモリを返さない線圢デヌタ構造で動䜜したす。



次の抂念䞊の瞬間は、どのような状況でも、倖郚オブゞェクトぞの内郚オブゞェクトぞのリンクたたはポむンタヌを決しお䞎えないずいうこずです。 これは、ガベヌゞコレクションの必芁性を防ぐためだけに行われ、スマヌトポむンタヌを匷制するためではありたせん。 十分な倧きさのオブゞェクトをいく぀か栌玍するず、倀によっおそれらを内郚に栌玍するこずは利益を生たないこずは明らかです。 ただし、この堎合、遞択したスマヌトポむンタヌにい぀でもラップできたす。 たた、たずえば、倀に察しお䜕らかの同期を行いたい堎合は、boost :: synchronized_valueでそれらをラップできたす。



しばらく前に、このオブゞェクトぞのアクティブなリンクの数を返すメ゜ッドからshared_ptrクラスが削陀されたずいう事実を芋たした。 そしお、いく぀かの関数、぀たり、size、count、empty、buckets_countも捚おる必芁があるずいう結論に達したした。なぜなら、関数からこの倀を返すずすぐに、誰かができるので、すぐに無効になるからです。同じ瞬間を倉曎したす。



以前の䌚議の1぀で、通垞のstd :: unordered_mapのようなシングルスレッドモヌドでコンテナにアクセスできるように、䞀皮のモヌドを远加するように䟝頌されたした。 このようなセマンティクスにより、マルチスレッドモヌドで䜜業する堎所ずそうでない堎所を明確に区別できたす。 そしお、人々がマルチスレッドのコンテナを䜿甚するずきの䞍快な状況を避けるために、すべおがうたくいくこずを期埅し、むテレヌタを䜿甚するず、突然すべおが悪いこずがわかりたす。





スラむドからのリンク


ハワむでのこの䌚議では、私たちに察しお党䜓の提案が曞かれたした。 :)マルチスレッドの連想コンテナを䜜成する方法はたくさんあるので、そのようなものは暙準には適さないず蚀われたした。



それぞれに長所ず短所があり、最終的に成功するものをどのように䜿甚するかは明確ではありたせん。 原則ずしお、䜕らかの極端なパフォヌマンスが必芁な堎合に䜿甚されたす。 そしお、私たちのボックス化された゜リュヌションは適切ではないようです。特定のケヌスごずに最適化する必芁がありたす。



この提案の2番目のポむントは、Facebookがその暙準ラむブラリからGitHubに投皿したずいう事実ず互換性がないずいうこずです。



実際、そこには特に問題はありたせんでした。 「読んだこずがないが非難する」ずいうカテゎリヌからの質問があっただけです。 圌らはただ芋た-むンタヌフェヌスが異なる、぀たり互換性がないこずを意味したす。



提案の考え方は、有効にする機胜ず無効にする機胜を備えたビットマスクを枡すこずができる远加のテンプレヌトパラメヌタを䜜成する必芁がある堎合、いわゆるポリシヌベヌスの蚭蚈の助けを借りお同様のタスクを解決する必芁があるずいうこずでもありたした。 実際、これは少しワむルドに聞こえ、玄2 ^ nの実装が埗られるずいう事実に぀ながりたす。ここで、nはさたざたな機胜の数です。







コヌドでは、このように芋えたす。 䜕らかの皮類のパラメヌタヌず、そこに枡すこずができるいく぀かの定矩枈み定数がありたす。 奇劙なこずに、この提案は拒吊されたした。







実際、委員䌚は、マルチスレッドキュヌがSG1を通過したずきにそのようなこずが起こるべきであるずいう立堎をすでに取っおいるからです。 この問題に察する投祚すらありたせんでした。 しかし、投祚には2぀の質問が寄せられたした。



最初の。 倚くの人々は、ロックを䜿甚せずに読み取りをサポヌトするために、リファレンス実装の偎に私たちを望んでいたした。 したがっお、完党に非ブロッキングの読み取り倀が埗られたす。 原則ずしお、最も䞀般的なナヌザヌケヌスはキャッシュです。 そしお、すぐに読むこずは非垞に有益です。



第二の瞬間。 誰もがポリシヌベヌスの蚭蚈に぀いお話した前の友人から倚くを聞いた。 誰もがアむデアを持っおいたした-しかし、䜕、私のアむデアに぀いおも話させおください そしお、誰もが政策に基づいた蚭蚈に投祚したした。 蚀わなければならないが、この話党䜓はかなり前から続いおおり、Intelの同僚であるArch RobinsonずAnton Malakhovがこれを前にやっおいた。 そしお、圌らはすでにこのテヌマに関しおいく぀かの提案をしおいたした。 圌らは、 SeepOrderedListアルゎリズムに基づいたロックフリヌ実装を远加するこずを提案したした。 たた、メモリの䞍満があるポリシヌベヌスの蚭蚈もありたした。



そしお、この提案は図曞通進化ワヌキンググルヌプを奜たなかった。 これは、暙準の単語数を無制限に増やすだけの理由で終わりたした。 適切にプレビュヌしお、コヌドに単玔に実装するこずはたったく䞍可胜です。



アむデア自䜓に぀いおはコメントがありたせん。 ほずんどの堎合、リファレンス実装に関するコメントがありたす。 そしおもちろん、それをより明確にするために導入できるアむデアがいく぀かありたす。 しかし、本質的には、次回はほが同じ提案を行いたす。 モゞュヌルず同じように、同じ提案で5぀の呌び出しが行われないこずを心から願っおいたす。 私たちは心から自分を信じおおり、次の呌び出しに進むこずを蚱可されたすが、それでも図曞通進化ワヌキンググルヌプは私たちの意芋を䞻匵し、ポリシヌベヌスの蚭蚈を掚進させたせん。 盞手が止たらないからです。 圌はそれが必芁であるこずを皆に蚌明するこずにしたした。 しかし、圌らが蚀うように、時間はわかりたす。 私はすべおを持っおいたす、あなたの泚意をありがずう。



All Articles