みなさんこんにちは。
「あの人も読んでる」、第17回目の投稿です。maguro (X @yusuktan)がお届けします。
前回の記事でJetBrains TVのチャンネルを紹介した際、Rust界隈で著名なJon Gjengsetさんのインタビュー動画を取り上げました。その動画をきっかけにしてか、優秀なYouTubeのレコメンドアルゴリズムが、あるチャンネルをレコメンドしてくれました。それがJane StreetのYouTubeチャンネルです。
Jane Streetは、世界有数のトレーディング企業で、関数型プログラミング言語OCamlを全面的に採用していることでも知られています。そのJane Streetが運営するYouTubeチャンネルでは、ソフトウェアエンジニアリングに関する非常に質の高いトーク動画が多数公開されています。
今回は、このJane Streetチャンネルで公開された動画を2つご紹介します。また、そのうちの1つの動画と関連するテーマとして、僕が最近強く惹かれている「決定論的シミュレーションテスト(Deterministic Simulation Testing, DST)」に着目して、金融に特化したデータベースであるTigerBeetleについての記事も1つご紹介していきます。
Mutexは遅いのか?
まずは、僕がJane Streetチャンネルを発見するきっかけとなった動画から。前回の記事でも紹介したJon Gjengsetさんが、"Are Mutexes Slow?" というテーマで講演しています。
「Mutexは遅い。読み取りが多い処理ならReader-Writer Lock(RWLock)を使うべきだ」―― これは並行プログラミングでよく耳にするアドバイスです。しかし、Gjengsetさんが実際にベンチマークを取ると、予想に反する結果が現れます。
読み取り専用の処理であるにもかかわらず、スレッド数を増やすとRWLockはMutexよりも遅くなるのです。
真のボトルネック:MESIプロトコル
この現象の原因は、ロックの仕組みそのものではなく、CPUキャッシュのコヒーレンス(一貫性維持)にある、とGjengsetさんは説明します。
現代のCPUでは、各コアがL1、L2、L3キャッシュを通じてデータに高速アクセスしています。複数のコアが同じメモリ領域(キャッシュライン:64バイト単位)を扱う際には、MESIプロトコル(Modified, Exclusive, Shared, Invalid)というルールに基づいてデータの一貫性が保たれます[1]。
ここで重要なのは、共有データに書き込みを行うには、他のすべてのコアのキャッシュを無効化(Invalid)して自分だけが独占(Exclusive)する状態を作る必要があるということです。このコア間通信のコストは、L1キャッシュへのアクセスに比べて約30倍も遅い。これこそがパフォーマンス低下の根本原因です。
RWLockで「読み取りロック」を取得する処理は、内部的には「現在のReader数を記録するカウンターへの書き込み(インクリメント)」です。つまり、100個のスレッドが読み取りロックを取ろうとすると、100個のコアがすべて順番にキャッシュラインを独占してカウンターを書き換える「キャッシュラインのピンポン」が発生してしまいます。

