Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 18967] ファイルの概要

このコミットは、Go言語の公式ドキュメントの一部である doc/go1.3.html ファイルに対する変更です。このファイルは、Go 1.3リリースにおける主要な変更点や新機能、改善点について説明するリリースノートの役割を担っています。

具体的には、このコミットはGo 1.3のメモリモデルに関するセクションを更新し、バッファ付きチャネルをセマフォとして使用するイディオムが、Goのメモリモデルによって明示的に許可されていることを明確に説明しています。これは言語仕様の変更ではなく、既存の動作に関する明確化であり、プログラマがこのパターンを安心して利用できるようにするための重要なドキュメントの更新です。

コミット

commit a4380927eb2d0070a936666e90a979f0f258bb0f
Author: Rob Pike <r@golang.org>
Date:   Thu Mar 27 11:45:51 2014 +1100

    doc/go1.3.html: explain the change to the memory model
    
    LGTM=iant, rsc
    R=rsc, iant, mtj
    CC=golang-codereviews
    https://golang.org/cl/80260044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/a4380927eb2d0070a936666e90a979f0f258bb0f

元コミット内容

doc/go1.3.html: explain the change to the memory model
    
LGTM=iant, rsc
R=rsc, iant, mtj
CC=golang-codereviews
https://golang.org/cl/80260044

変更の背景

この変更の背景には、Go言語の並行処理における重要な要素である「メモリモデル」と「チャネル」の間の相互作用に関する明確性の欠如がありました。Goのメモリモデルは、複数のGoroutineが共有データにアクセスする際の動作を定義し、データ競合を防ぎ、プログラムの予測可能性を保証するためのルールを提供します。

以前のGoのドキュメントやメモリモデルの記述では、バッファ付きチャネルをセマフォとして利用する一般的なイディオム(例えば、並行処理の数を制限するためなど)が、メモリモデルの観点から明示的に保証されているかどうかが不明確でした。開発者は経験的にこのパターンが機能することを知っていましたが、それがGoのメモリモデルによって正式にサポートされているのか、あるいは単なる実装の詳細に依存しているのか、という疑問がありました。

コミット前の doc/go1.3.html の該当箇所には TODO コメントがあり、この曖昧さを解消する必要があることが示されていました。具体的には、「初期のGoドキュメントではチャネルをセマフォとして使う例が示されていたが、Goのメモリモデルがこのイディオムが許可されていることを明示するように更新された」という内容が記述される予定でした。

このコミットは、その TODO を解消し、Go 1.3のメモリモデルがバッファ付きチャネルをセマフォとして使用することを正式にサポートしていることを明確にすることで、開発者がこの強力な並行処理パターンを自信を持って利用できるようにすることを目的としています。これは言語の動作を変更するものではなく、既存の動作に対する公式な「明確化」であり、Goの並行処理の堅牢性を高める上で重要な意味を持ちます。

前提知識の解説

Goのメモリモデル

Goのメモリモデルは、複数のGoroutineが共有データにアクセスする際の動作を定義する一連のルールです。これは、データ競合(data race)を防ぎ、プログラムの実行結果が予測可能であることを保証するために不可欠です。メモリモデルは、特定の操作(例えば、チャネルの送受信、sync パッケージのプリミティブの使用など)が「happens before」関係を確立することを保証します。

  • Happens Before (先行発生): あるイベントAが別のイベントBより先行発生するということは、Aのメモリ効果がBから見えることを意味します。もしAがBより先行発生し、BがCより先行発生するならば、AはCより先行発生します(推移律)。データ競合は、少なくとも1つのアクセスが書き込みであり、かつそれらのアクセスが先行発生関係によって順序付けられていない場合に発生します。

Goのチャネル

チャネルは、Goroutine間で値を送受信するための通信メカニズムです。Goの並行処理の根幹をなす要素であり、共有メモリによる通信ではなく、通信による共有メモリ("Don't communicate by sharing memory; share memory by communicating.")というGoの哲学を体現しています。

  • バッファなしチャネル: 容量が0のチャネルです。送信操作は受信操作が準備できるまでブロックし、受信操作は送信操作が準備できるまでブロックします。これにより、送信と受信の間で同期が確立されます。
  • バッファ付きチャネル: 容量が1以上のチャネルです。チャネルが満杯でない限り、送信操作はブロックしません。チャネルが空でない限り、受信操作はブロックしません。バッファが満杯になると送信はブロックし、バッファが空になると受信はブロックします。

セマフォ

セマフォは、並行プログラミングにおける同期プリミティブの一つで、共有リソースへのアクセスを制御するために使用されます。セマフォは、内部にカウンタを持ち、以下の2つの主要な操作を提供します。

  • P操作 (Wait/Acquire): カウンタをデクリメントします。カウンタが0の場合、操作はブロックされます。これにより、リソースの取得を表現します。
  • V操作 (Signal/Release): カウンタをインクリメントします。ブロックされているP操作があれば、それを解放します。これにより、リソースの解放を表現します。

セマフォは、特定の数のGoroutineのみが同時にクリティカルセクションに入ることができるように、並行処理の数を制限するためによく使用されます(カウンティングセマフォ)。

技術的詳細

このコミットが明確にしている技術的詳細は、Go 1.3のメモリモデルにおけるバッファ付きチャネルの新しいルール、特にそれがセマフォとしてどのように機能するかという点に集約されます。

Goのメモリモデルは、バッファなしチャネルの送受信が先行発生関係を確立することを既に保証していました。つまり、バッファなしチャネルへの送信が完了する前に、そのチャネルからの受信が開始されることはありません。

Go 1.3で追加された(そしてこのドキュメントで明確化された)新しいルールは、バッファ付きチャネルに関するものです。このルールは以下のように述べられます。

容量 C のバッファ付きチャネルにおける k 番目の受信は、そのチャネルからの k+C 番目の送信の完了より前に同期される。

このルールは、バッファ付きチャネルがカウンティングセマフォとして機能することを保証します。具体的には:

  1. セマフォの取得 (Acquire): バッファ付きチャネルへの送信操作 (ch <- value) は、セマフォの取得(P操作)に相当します。チャネルのバッファが満杯でない限り、送信はブロックされずに続行されます。これは、セマフォのカウンタがまだ正であり、リソースが利用可能であることを意味します。チャネルが満杯の場合、送信はブロックされ、これはセマフォのカウンタが0であり、リソースが利用できないことを意味します。
  2. セマフォの解放 (Release): バッファ付きチャネルからの受信操作 (<-ch) は、セマフォの解放(V操作)に相当します。受信が成功すると、チャネルのバッファから要素が一つ取り除かれ、これにより、ブロックされていた送信操作(もしあれば)が再開される可能性があります。これは、セマフォのカウンタがインクリメントされ、リソースが解放されたことを意味します。

このルールにより、バッファ付きチャネルの容量 C は、同時に許可される並行操作の最大数として機能します。例えば、容量1のバッファ付きチャネルはバイナリセマフォ(ミューテックス)として機能し、容量 N のチャネルは N 個のリソースを管理するカウンティングセマフォとして機能します。

この明確化は、Go言語自体の動作を変更するものではありません。むしろ、Goのランタイムがチャネルの送受信をどのように処理し、それがメモリの可視性にどのような影響を与えるかについて、既存の保証をより厳密に定義したものです。これにより、開発者はバッファ付きチャネルをセマフォとして使用する際に、データ競合の心配なく、その同期特性に依存できることが保証されます。これは、並行処理の設計において、より安全で予測可能なコードを書くための基盤を提供します。

コアとなるコードの変更箇所

--- a/doc/go1.3.html
+++ b/doc/go1.3.html
@@ -46,11 +46,12 @@ windows 2000 removed (CL 74790043)
 <h2 id="memory">Changes to the memory model</h2>
 
 <p>
-TODO:
-early go documentation suggested using a channel as a semaphore like this: (previous example).
-the go memory model has been updated to make explicit that this idiom is allowed.  (new example).\n-the previous example is also correct, just requiring needless func init work.\n-(CL 75130045)\n+The Go 1.3 memory model <a href="https://codereview.appspot.com/75130045">adds a new rule</a>\n+concerning sending and receiving on buffered channels,\n+to make explicit that a buffered channel can be used as a simple\n+semaphore, using a send into the\n+channel to acquire and a receive from the channel to release.\n+This is not a language change, just a clarification about an expected property of communication.\n </p>
 
 <h2 id="impl">Changes to the implementations and tools</h2>

コアとなるコードの解説

このコミットによる doc/go1.3.html の変更は、Go 1.3のメモリモデルに関するセクション (<h2 id="memory">Changes to the memory model</h2>) の <p> タグ内のコンテンツを更新しています。

変更前:

変更前は、TODO コメントが含まれており、バッファ付きチャネルをセマフォとして使用するイディオムに関するメモリモデルの明確化が必要であることが示唆されていました。具体的な内容は以下の通りです。

  • TODO:: 未完了のタスクを示す。
  • early go documentation suggested using a channel as a semaphore like this: (previous example).: 以前のGoドキュメントでチャネルをセマフォとして使う例が示されていたこと。
  • the go memory model has been updated to make explicit that this idiom is allowed. (new example).: Goメモリモデルがこのイディオムを明示的に許可するように更新されたこと。
  • the previous example is also correct, just requiring needless func init work.: 以前の例も正しかったが、不要な func init 作業が必要だったこと。
  • (CL 75130045): 関連する変更リスト(Code Review)の番号。

この TODO は、ドキュメントがまだ完成しておらず、メモリモデルの変更に関する説明が不足している状態を示していました。

変更後:

変更後には、TODO コメントが削除され、Go 1.3のメモリモデルにおけるバッファ付きチャネルの役割に関する明確な説明が追加されました。

  • The Go 1.3 memory model <a href="https://codereview.appspot.com/75130045">adds a new rule</a> concerning sending and receiving on buffered channels,: Go 1.3メモリモデルが、バッファ付きチャネルの送受信に関する「新しいルール」を追加したことを明記しています。ここで参照されている CL 75130045 は、この新しいルールが導入された実際のコード変更を示しています。
  • to make explicit that a buffered channel can be used as a simple semaphore, using a send into the channel to acquire and a receive from the channel to release.: この新しいルールが、バッファ付きチャネルをシンプルなセマフォとして使用できることを明確にするためのものであると説明しています。具体的には、チャネルへの送信がセマフォの「取得」に、チャネルからの受信がセマフォの「解放」に対応することを述べています。
  • This is not a language change, just a clarification about an expected property of communication.: この変更が言語自体の変更ではなく、通信の「期待される特性」に関する単なる明確化であることを強調しています。これは、既存のGoプログラムの動作が変わるわけではなく、Goの並行処理モデルの保証がより厳密に定義されたことを意味します。

この変更により、Go 1.3のリリースノートは、バッファ付きチャネルをセマフォとして使用するパターンがGoのメモリモデルによって正式にサポートされ、安全であることが明確に示されるようになりました。これにより、開発者はこのイディオムを自信を持って利用し、より堅牢な並行アプリケーションを構築できるようになります。

関連リンク

参考にした情報源リンク