プログラミング
書籍レビュー:並列プログラミングは難しいか?もしそうなら、どうすればよいか?
Book review: Is parallel programming hard, and, if so, what can you do about it? (ahelwer.ca)
要約
この記事は、LinuxカーネルのRCU同期メカニズムの作者であるPaul E. McKenneyによる無料オンライン教科書『Is Parallel Programming Hard, And, If So, What Can You Do About It?』のレビューである。著者は、教科書の構成、特に内部リンクの多さによるナビゲーションの困難さを指摘しつつも、CPUの動作原理やコンパイラ・CPUによる予期せぬ最適化など、並列プログラミングの難しさに関する解説が自身のレベルに合っていたと評価している。
全文翻訳
Paul E. McKenney著、LinuxカーネルのRCU同期メカニズムの作者である無料オンライン教科書『Is Parallel Programming Hard, And, If So, What Can You Do About It?』についての私の考えを述べます。この教科書の大部分を読み、十分に満足したので、近い将来さらに読むことはないだろうと思い、すべてがまだ新鮮なうちにこのレビューを書きたいと思いました。 設定と状況 ここでは、この教科書を読み始めたときの私の考え方/人生の段階と物理的な状況について話します。これはレシピサイトにあるような、退屈な個人的な風味の前置きのようなものかもしれませんので、興味がなければ先に進んでください。私の専門的な人生は過去10年間、TLA⁺と分散システムを中心に展開してきましたが、変化の時期が来たと考えていました。過渡的で感情的に激動の時期でした!2022年にLeanに移行しようとしましたが(失敗しました)、研究者の量子情報処理の結果を形式化する、信じられないほどニッチで存在しない仕事を得ることを望んでいました。それに燃え尽きてしまいましたが、最近の自動定理証明の進歩を考えると、一時的に先見の明があった私の神経系が私を危険から回避させてくれたのかもしれません。このようにして、2026年のコロンビア(ミズーリ州)で開催されたSoftware Should Workカンファレンスに参加した際の歴史と文脈がありました。カンファレンスでは多くの良い講演がありましたが、特にFilip PizloによるFil-Cの講演が気に入りました:Filとも、インタープリタと並列処理についてかなり話しました。TLA⁺と分散システムから並列処理についてかなり知識があると思っていましたが、Filはロックフリーのガベージコレクタを書くことの難しさについて語り、私は並列処理について実際にはほとんど何も知らないことに気づきました(何も知らないと感じるのは良いカンファレンスの印です)。Filはまた、TLA⁺は文字通り並列に発生するイベント(マルチコアCPUの実際の可能性!)を推論するのに役立たない(少なくとも人間工学的ではない)可能性があり、線形化可能性のための並列アルゴリズムの分析の重要性についても言及しました。これは、分散システムの意味での線形化可能性という概念を、私はなんとなく理解していました。これらすべてが非常に魅力的だと思われたので、ミューテックスベースまたはメッセージパッシングパターンに焦点を当てたものよりも、ロックフリーの側面に焦点を当てた並列処理の教科書を探しました。『Is Parallel Programming Hard, And, If So, What Can You Do About It?』は、より具体的なロックフリーデータ構造の書き方に関する教科書ではなく、一般的な並列プログラミングとCPUキャッシュ効果に焦点を当てているため、この要件に合致しているように思われました。また、HNで(2023年、2021年、2020年、2015年、2014年、2011年に)数回、中程度に興味深いスレッドがありました。正確な「正しい」教科書を見つけようと分析麻痺に時間を費やすのは無駄だとは思いません(これは本当に単なる先延ばしの巧妙な方法です)、なのでそれは十分良いと思われました。この教科書を読んだ物理的な場所は、カナダの静かで木々に囲まれた場所にある私の家族を訪ねる1.5週間の休暇でした。2026年は特にひどい蚊の季節でもありました。そのため、私は涼しい網戸付きのパティオに座って、何百もの警備員に監視されながら、ポストを離れないように熱心に過ごしました:衛星とセルタワーにより、国のより遠隔地でも邪魔なほど良いインターネット接続が可能になりましたが、それ以外は最適な教科書読書場所でした。 教科書の形式 教科書の実際の構造についていくつか簡単なメモをします。それは、少なくとも3つの異なる形式、すべてPDFで利用可能です:科学論文のような二段組形式 余白の大きい一段組形式 余白のない一段組形式 後者の形式は、私のPine64 PineNoteで読むのに最適です。教科書には膨大な数の内部リンクが含まれています。これらのリンクの一部は、知識チェックの質問ボックスで使用されており、リンクをクリックすると質問の回答に移動します。他のリンクは、図やセクションが言及されるたびに、または大量の脚注や引用のために使用されます。残念ながら、後者は非常に迷惑であり、おそらく少なくとも80%削減されるべきです。電子リーダーに物理的なページめくりボタンがない場合、本の読書体験は、ページをめくろうとしたときにこれらのリンクのいずれかを誤って押してしまい、どこに送られるか分からないという状態を絶えず繰り返すことになります。電子書籍は、これなしでもナビゲートするのが十分に混乱するのに、繰り返しページめくりをタップして2つのセクションを素早く行き来することが不可能になりました。リンクをクリックしたい場合、場所によっては2つのリンクが隣接していることがあり、タッチスクリーンでは一方のリンクではなくもう一方を確実にクリックする精度がありません。すべてのリンクを無効にするという解決策がありますが、そうすると非常に優れた知識チェックの質問にアクセスできなくなります。なので、私はただそれに耐えました。 教科書の内容 - 導入章 教科書は、私のレベルにとってほぼ完璧な教材の提示でした。本は、章3「ハードウェアとその習慣」でレースに突入する前に、 nice light な導入と動機付けの章から始まります。ここで、最新のCPUがどのように高レベルで動作するか、何がそれらを速くし、何がそれらを遅くするかを学びます。ユーモラスなイラストがたくさん含まれています!セクション3.2.1「ハードウェアシステムアーキテクチャ」は、CPUコアがキャッシュに存在しないメモリ位置に書き込むという単純化された説明を歩むにつれて、私にとって本当に面白くなりました。ここに一つの機会損失があります:私はMESIプロトコルについての基本的な説明から非常に恩恵を受けたでしょう。CPUキャッシュが並列読み書きをどのように仲介するかについて、本質的に直感を持っていませんでした。このセクションをよりよく理解するためにオンラインで検索中にMESIについて知りました。MESIはこの本の付録にしか言及されていません。しかし、MESIについて知ることで、本全体の理解が大幅に向上しました。MESIを学ぶことで、複数のCPUコアが同じデータ場所に文字通り同時に書き込むことはできないことも学びました!x86 CPUは実際には直接メモリに書き込むのではなく、キャッシュにのみ書き込みます(キャッシュ値は最終的にメモリにフラッシュされます)。x86 CPUコアは、そのアドレスを含むキャッシュラインの排他的所有権を持っている場合にのみ、特定のアドレスに書き込むことができます。別のコアが同時にそのアドレスに書き込もうとすると、キャッシュラインの排他的所有権が移動するのを待たなければなりません。したがって、文字通り同時に書き込むことは実際には起こりません。ただし、書き込まれるデータが複数のキャッシュラインにまたがる場合、書き込みが破損する可能性があります。 「ツールの紹介」と題された第4章は、完全に心を揺さぶるものでした。ここでは、十分な注意を払わずに並列プログラムを書くと、コンパイラが信じられないほど創造的な最適化を試み、完全に無意味な動作を引き起こすことを学びます!セクション4.3.4.1「共有変数いたずら」は、ロードテアリング、ストアテアリング、ロードフュージング、ストアフュージング、コード並べ替え、発明されたロード、発明されたストア(特にひどい)、ストア・トゥ・ロード変換、デッドコード削除などの恐ろしい事故をカバーしています。次に、コードがコンパイルを無事に生き延びたと仮定すると、章ではCPUがプログラムを実行するときに実際に引き起こす可能性のあるナンセンスについて説明します!この二重のトラブルにより、馴染みのあるミューテックスやメッセージパッシングを超えて、並列プログラムについてまともに考えることが困難になりました。この章で私が抱いた唯一の問題は、それがLinuxカーネルのコンテキストに非常に特化していることです。C++11とC11がstd::memory_orderのようなもので並列プログラミングを形式化するために行った作業について学びたかったでしょう。これらは、セクション4.2.6と4.2.7、「アトミック操作(C11)」と「アトミック操作(モダンGCC)」で短い段落しか与えられていませんでした。ACCESS_ONCE()とWRITE_ONCE()マクロが単にvolatile*にキャストするだけで、それがコンパイラを怖がらせるのに十分だったという漠かな考えを持って章を脱出しました。ベンignなデータ競合がエラーであったかどうかについての議論など、非常に興味深い歴史的な発展は完全に省略されていました。 教科書の内容 - 主要章