[インデックス 17980] ファイルの概要
このコミットは、Go言語の公式FAQドキュメントである doc/go_faq.html
の内容を修正するものです。具体的には、Goの並行処理の文脈で「スレッド (threads)」という用語が使われている箇所を、より正確な「ゴルーチン (goroutines)」という用語に置き換えています。
コミット
このコミットは、Go言語のドキュメントにおける用語の正確性を向上させることを目的としています。Goの並行処理モデルにおいて、OSスレッドとゴルーチンは異なる概念であり、Goプログラミングにおいては通常、ゴルーチンを直接操作します。この変更は、Goの並行処理の哲学と実装をより正確に反映させるためのものです。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8189605a9681385c8464d72a13541b683fe88cdd
元コミット内容
doc: change "threads" to "goroutines"
R=golang-dev, minux.ma, rsc
CC=golang-dev
https://golang.org/cl/40510049
変更の背景
Go言語は、その設計思想の中心に「並行性 (concurrency)」を据えています。Goの並行処理モデルは、OSが提供する「スレッド」を直接扱うのではなく、Goランタイムが管理する軽量な実行単位である「ゴルーチン」と、それらのゴルーチン間の通信を安全に行うための「チャネル (channels)」を主要な要素としています。
初期のドキュメントや議論では、並行処理の一般的な概念を説明する際に、既存のプログラミング言語で広く使われている「スレッド」という用語が便宜的に使われることがありました。しかし、GoのゴルーチンはOSスレッドとは異なる特性(非常に軽量であること、Goランタイムがスケジューリングを行うことなど)を持つため、この用語の混同はGoの並行処理モデルに対する誤解を招く可能性がありました。
このコミットは、Goの並行処理に関する公式ドキュメントにおいて、より正確でGoらしい用語を使用することで、読者がGoの並行処理モデルを正しく理解できるようにするための改善の一環です。特に、マップの並行アクセスに関するFAQのセクションで「スレッド」という言葉が使われていたため、これを「ゴルーチン」に修正することで、Goの並行処理の文脈におけるマップの安全性に関する議論がより明確になります。
前提知識の解説
ゴルーチン (Goroutines)
ゴルーチンは、Go言語における並行処理の基本単位です。OSスレッドと比較して非常に軽量であり、数千、数万といった大量のゴルーチンを同時に生成・実行することが可能です。ゴルーチンはGoランタイムによってスケジューリングされ、複数のOSスレッドに多重化されて実行されます。これにより、プログラマはOSスレッドの管理(スタックサイズ、コンテキストスイッチのコストなど)を意識することなく、高レベルな並行処理を記述できます。
スレッド (Threads)
スレッドは、オペレーティングシステムが提供する実行の基本単位です。各スレッドは独自のプログラムカウンタ、レジスタセット、スタックを持ち、プロセス内で並行して実行されます。OSスレッドはゴルーチンに比べてリソース消費が大きく、コンテキストスイッチのオーバーヘッドも高いため、大量に生成するとパフォーマンスの問題を引き起こす可能性があります。多くのプログラミング言語では、並行処理を実現するために直接OSスレッドを操作しますが、Goはゴルーチンという抽象化レイヤーを提供しています。
Goの並行処理モデル
Goの並行処理モデルは、「Communicating Sequential Processes (CSP)」という理論に基づいています。これは、並行に動作するプロセス(Goではゴルーチン)が、共有メモリを介してではなく、チャネルを介してメッセージを交換することで協調動作するという考え方です。このモデルは、共有メモリによる並行処理で発生しがちなデータ競合やデッドロックといった問題を回避しやすくします。
Goにおけるマップ (Map) の並行アクセス
Goの組み込み型であるマップは、複数のゴルーチンから同時に読み書きされることを想定して設計されていません。複数のゴルーチンが同時にマップを読み書きしようとすると、データ競合が発生し、予測不能な動作やパニック(プログラムの異常終了)を引き起こす可能性があります。そのため、マップを複数のゴルーチンから安全にアクセスする必要がある場合は、sync.Mutex
などの同期プリミティブを使用して、アクセスを排他的に制御する必要があります。このコミットで修正されたFAQのセクションは、まさにこのマップの並行アクセスに関するものです。
技術的詳細
このコミットの技術的詳細は、コードの機能的な変更ではなく、ドキュメントの正確性に関するものです。Goのランタイムは、ゴルーチンをOSスレッドにマッピングして実行します。このマッピングは、Goランタイムのスケジューラによって動的に行われます。プログラマが go
キーワードを使ってゴルーチンを起動すると、Goランタイムはそれを既存のOSスレッド上で実行するか、必要に応じて新しいOSスレッドを生成して実行します。
「スレッド」という用語は、OSレベルの並行処理の概念を指します。一方、「ゴルーチン」はGo言語が提供する軽量な並行処理の抽象化です。Goのプログラマは通常、ゴルーチンを直接扱い、OSスレッドの管理についてはGoランタイムに任せます。したがって、Goの並行処理について議論する際には、「ゴルーチン」という用語を使用することが、Goの設計思想と実装をより正確に反映します。
この変更は、特にマップの並行アクセスに関するFAQの回答において重要です。マップの操作がアトミックではないという決定は、一般的な使用シナリオでは複数の「ゴルーチン」からの安全なアクセスを必要としないという前提に基づいています。もし必要であれば、マップはすでに同期されたより大きなデータ構造の一部であると想定されます。この文脈で「スレッド」という言葉を使うと、Goの並行処理モデルの理解を妨げる可能性があります。Goのマップは、OSスレッドレベルでの同期ではなく、ゴルーチンレベルでの同期(例えば、sync.Mutex
を用いた排他制御)を必要とします。
コアとなるコードの変更箇所
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -446,7 +446,7 @@ Why are map operations not defined to be atomic?</h3>
<p>
After long discussion it was decided that the typical use of maps did not require
-safe access from multiple threads, and in those cases where it did, the map was
+safe access from multiple goroutines, and in those cases where it did, the map was
probably part of some larger data structure or computation that was already
synchronized. Therefore requiring that all map operations grab a mutex would slow
down most programs and add safety to few. This was not an easy decision,
コアとなるコードの解説
変更は doc/go_faq.html
ファイルの1箇所のみです。
-safe access from multiple threads, and in those cases where it did, the map was
- この行は、変更前のドキュメントの内容を示しています。「複数のスレッドからの安全なアクセス」という表現が使われています。
+safe access from multiple goroutines, and in those cases where it did, the map was
- この行は、変更後のドキュメントの内容を示しています。「複数のゴルーチンからの安全なアクセス」という表現に修正されています。
この修正は、Goの並行処理の文脈において、マップの安全なアクセスについて議論する際に、「スレッド」ではなく「ゴルーチン」というGo固有の用語を使用することの重要性を示しています。これにより、Goの並行処理モデルの正確な理解が促進されます。
関連リンク
- Go Concurrency Patterns - Goの並行処理パターンに関する公式ブログ記事
- Effective Go - Concurrency - Effective Goにおける並行処理のセクション
- A Tour of Go - Concurrency - Goの並行処理に関するチュートリアル
参考にした情報源リンク
- Go言語公式ドキュメント
- Go言語の並行処理に関する一般的な知識
- コミットメッセージと差分情報