[インデックス 19085] ファイルの概要
このコミットは、Go言語の標準ライブラリ sync
パッケージ内の sync.Pool
型に関するドキュメンテーションを改善することを目的としています。具体的には、sync.Pool
の目的、適切な使用例、および不適切な使用例をより明確に説明することで、開発者がこの機能を正しく理解し、効果的に利用できるようにしています。
コミット
sync.Pool: better documentation
Explain what its purpose is and give examples of good and bad use.
Fixes #7167.
LGTM=dvyukov, rsc
R=golang-codereviews, dvyukov, rsc
CC=golang-codereviews
https://golang.org/cl/85880044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a8787cd820fb39575efed14617dde2fb8131b354
元コミット内容
commit a8787cd820fb39575efed14617dde2fb8131b354
Author: Rob Pike <r@golang.org>
Date: Thu Apr 10 05:45:18 2014 +1000
sync.Pool: better documentation
Explain what its purpose is and give examples of good and bad use.
Fixes #7167.
LGTM=dvyukov, rsc
R=golang-codereviews, dvyukov, rsc
CC=golang-codereviews
https://golang.org/cl/85880044
---
src/pkg/sync/pool.go | 42 +++++++++++++++++++++++++-----------------
1 file changed, 25 insertions(+), 17 deletions(-)
diff --git a/src/pkg/sync/pool.go b/src/pkg/sync/pool.go
index ca49d21a0d..a078cdc920 100644
--- a/src/pkg/sync/pool.go
+++ b/src/pkg/sync/pool.go
@@ -16,27 +16,35 @@ const (
poolLocalCap = poolLocalSize/unsafe.Sizeof(*(*interface{})(nil)) - 1
)
-// A Pool is a set of temporary objects that may be individually saved
-// and retrieved.
+// A Pool is a set of temporary objects that may be individually saved and
+// retrieved.
//
-// Any item stored in the Pool may be removed automatically by the
-// implementation at any time without notification.
-// If the Pool holds the only reference when this happens, the item
-// might be deallocated.
+// Any item stored in the Pool may be removed automatically at any time without
+// notification. If the Pool holds the only reference when this happens, the
+// item might be deallocated.
//
// A Pool is safe for use by multiple goroutines simultaneously.
//
-// Pool's intended use is for free lists maintained in global variables,
-// typically accessed by multiple goroutines simultaneously. Using a
-// Pool instead of a custom free list allows the runtime to reclaim
-// entries from the pool when it makes sense to do so. An
-// appropriate use of sync.Pool is to create a pool of temporary buffers
-// shared between independent clients of a global resource. On the
-// other hand, if a free list is maintained as part of an object used
-// only by a single client and freed when the client completes,
-// implementing that free list as a Pool is not appropriate.
+// Pool's purpose is to cache allocated but unused items for later reuse,
+// relieving pressure on the garbage collector. That is, it makes it easy to
+// build efficient, thread-safe free lists. However, it is not suitable for all
+// free lists.
+//
+// An appropriate use of a Pool is to manage a group of temporary items
+// silently shared among and potentially reused by concurrent independent
+// clients of a package. Pool provides a way to amortize allocation overhead
+// across many clients.
+//
+// An example of good use of a Pool is in the fmt package, which maintains a
+// dynamically-sized store of temporary output buffers. The store scales under
+// load (when many goroutines are actively printing) and shrinks when
+// quiescent.
+//
+// On the other hand, a free list maintained as part of a short-lived object is
+// not a suitable use for a Pool, since the overhead does not amortize well in
+// that scenario. It is more efficient to have such objects implement their own
+// free list.
//
-// This is an experimental type and might not be released.
type Pool struct {
// The following fields are known to runtime.
next *Pool // for use by runtime
@@ -173,7 +181,7 @@ func (p *Pool) getSlow() (x interface{}) {\n return\n }\n \n-// pin pins current goroutine to P, disables preemption and returns poolLocal pool for the P.\n+// pin pins the current goroutine to P, disables preemption and returns poolLocal pool for the P.\n // Caller must call runtime_procUnpin() when done with the pool.\n func (p *Pool) pin() *poolLocal {\n pid := runtime_procPin()\n```
## 変更の背景
`sync.Pool` は、Go言語のガベージコレクタ (GC) の負荷を軽減し、一時的なオブジェクトの再利用を促進するための強力なメカニズムですが、その挙動や適切な使用方法について、初期のドキュメンテーションでは十分に説明されていませんでした。多くの開発者が `sync.Pool` を誤解し、不適切なシナリオで使用することで、期待されるパフォーマンス上の利点が得られなかったり、かえって複雑性や予期せぬバグを引き起こしたりするケースがありました。
このコミットは、GitHub Issue #7167「sync: document Pool better」に対応するものです。このIssueは、`sync.Pool` のドキュメンテーションを改善し、その意図された目的、特にグローバルなオブジェクトの管理における役割を明確にすることを求めていました。開発者が `sync.Pool` を単なる汎用的なオブジェクトプールとしてではなく、GCのプレッシャーを軽減するための特定のユースケースに特化したツールとして理解できるように、より詳細な説明と具体的な使用例を提供する必要がありました。
## 前提知識の解説
このコミットの変更内容を深く理解するためには、以下のGo言語の概念に関する前提知識が必要です。
1. **ガベージコレクション (GC)**: Go言語は自動メモリ管理(ガベージコレクション)を採用しています。プログラムがメモリを割り当てると、GCは不要になったメモリを自動的に解放します。しかし、頻繁なメモリ割り当てと解放はGCに負荷をかけ、プログラムの実行を一時的に停止させる(ストップ・ザ・ワールド)ことでレイテンシースパイクを引き起こす可能性があります。`sync.Pool` は、このGCの負荷を軽減することを目的としています。
2. **一時的なオブジェクト (Temporary Objects)**: プログラムの実行中に短期間だけ使用され、すぐに不要になるオブジェクトのことです。例えば、ネットワークリクエストの処理中に一時的に使用されるバッファや、データ変換のための中間構造体などがこれに該当します。
3. **フリーリスト (Free List)**: オブジェクトの再利用を目的としたデータ構造です。使用済みになったオブジェクトをすぐに解放せず、リストに保持しておき、次に同じ種類のオブジェクトが必要になったときにリストから取り出して再利用することで、メモリ割り当てのオーバーヘッドを削減します。`sync.Pool` は、このフリーリストを効率的に実装するための汎用的なメカニズムを提供します。
4. **ゴルーチン (Goroutine)**: Go言語の軽量な並行処理単位です。数千、数万のゴルーチンを同時に実行することが可能です。`sync.Pool` は複数のゴルーチンから同時に安全にアクセスできるように設計されています。
5. **`sync` パッケージ**: Go言語の標準ライブラリの一部で、並行処理における同期プリミティブ(ミューテックス、セマフォ、条件変数など)を提供します。`sync.Pool` もこのパッケージの一部であり、並行環境での安全なオブジェクト管理をサポートします。
6. **`fmt` パッケージ**: Go言語の標準ライブラリの一部で、フォーマットされたI/O(入出力)を提供します。このコミットのドキュメンテーションの例で `fmt` パッケージが `sync.Pool` を使用していることが言及されており、具体的なユースケースとして示されています。
## 技術的詳細
このコミットの主要な変更は、`src/pkg/sync/pool.go` ファイル内の `sync.Pool` 型のドキュメンテーションコメントの更新です。以前のドキュメンテーションは簡潔でしたが、`sync.Pool` の本質的な目的や、どのようなシナリオで有効であるか、あるいは避けるべきかを十分に伝えていませんでした。
新しいドキュメンテーションは、以下の点を明確にしています。
1. **目的の明確化**:
* 以前: "A Pool is a set of temporary objects that may be individually saved and retrieved." (Poolは個別に保存および取得できる一時的なオブジェクトのセットです。)
* 変更後: "Pool's purpose is to cache allocated but unused items for later reuse, relieving pressure on the garbage collector. That is, it makes it easy to build efficient, thread-safe free lists. However, it is not suitable for all free lists." (Poolの目的は、割り当てられたが未使用のアイテムを後で再利用するためにキャッシュし、ガベージコレクタへの負荷を軽減することです。つまり、効率的でスレッドセーフなフリーリストを簡単に構築できます。ただし、すべてのフリーリストに適しているわけではありません。)
この変更により、`sync.Pool` が単なるオブジェクトプールではなく、GCの負荷軽減という特定の目的を持つことが強調されています。
2. **GCとの相互作用の強調**:
* 以前のドキュメンテーションでも「Any item stored in the Pool may be removed automatically by the implementation at any time without notification. If the Pool holds the only reference when this happens, the item might be deallocated.」という記述はありましたが、その重要性が十分に伝わっていませんでした。
* 新しいドキュメンテーションでは、この点がより文脈の中で強調され、`sync.Pool` がキャッシュであり、オブジェクトの永続性を保証するものではないことが暗に示されています。
3. **適切な使用例の追加**:
* 「An appropriate use of a Pool is to manage a group of temporary items silently shared among and potentially reused by concurrent independent clients of a package. Pool provides a way to amortize allocation overhead across many clients.」
* 具体的な例として `fmt` パッケージが一時的な出力バッファを管理するために `sync.Pool` を使用していることが挙げられています。「An example of good use of a Pool is in the fmt package, which maintains a dynamically-sized store of temporary output buffers. The store scales under load (when many goroutines are actively printing) and shrinks when quiescent.」
これにより、`sync.Pool` が並行する独立したクライアント間で一時的なアイテムを共有し、割り当てオーバーヘッドを償却するのに適していることが示されています。
4. **不適切な使用例の追加**:
* 「On the other hand, a free list maintained as part of a short-lived object is not a suitable use for a Pool, since the overhead does not amortize well in that scenario. It is more efficient to have such objects implement their own free list.」
* これにより、短命なオブジェクトの一部として維持されるフリーリストには `sync.Pool` が不適切であることが明確にされています。これは、`sync.Pool` の管理オーバーヘッドが、そのシナリオでの割り当て削減の利点を上回る可能性があるためです。
5. **実験的タイプであることの記述の削除**:
* 以前のドキュメンテーションにあった「This is an experimental type and might not be released.」という記述が削除されました。これは、`sync.Pool` がGo 1.3で正式に導入され、安定したAPIとして認識されたことを示しています。
これらの変更は、`sync.Pool` の設計思想と、それがGoのランタイムおよびガベージコレクタとどのように相互作用するかについて、開発者の理解を深めることを目的としています。特に、`sync.Pool` がGCのプレッシャーを軽減するための「キャッシュ」であり、オブジェクトの寿命を保証するものではないという点が強調されています。
## コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は、`src/pkg/sync/pool.go` ファイル内の `Pool` 型の定義直前にあるドキュメンテーションコメントです。
具体的には、以下の部分が大幅に書き換えられています。
```diff
--- a/src/pkg/sync/pool.go
+++ b/src/pkg/sync/pool.go
@@ -16,27 +16,35 @@ const (
poolLocalCap = poolLocalSize/unsafe.Sizeof(*(*interface{})(nil)) - 1
)
-// A Pool is a set of temporary objects that may be individually saved
-// and retrieved.
+// A Pool is a set of temporary objects that may be individually saved and
+// retrieved.
//
-// Any item stored in the Pool may be removed automatically by the
-// implementation at any time without notification.
-// If the Pool holds the only reference when this happens, the item
-// might be deallocated.
+// Any item stored in the Pool may be removed automatically at any time without
+// notification. If the Pool holds the only reference when this happens, the
+// item might be deallocated.
//
// A Pool is safe for use by multiple goroutines simultaneously.
//
-// Pool's intended use is for free lists maintained in global variables,
-// typically accessed by multiple goroutines simultaneously. Using a
-// Pool instead of a custom free list allows the runtime to reclaim
-// entries from the pool when it makes sense to do so. An
-// appropriate use of sync.Pool is to create a pool of temporary buffers
-// shared between independent clients of a global resource. On the
-// other hand, if a free list is maintained as part of an object used
-// only by a single client and freed when the client completes,
-// implementing that free list as a Pool is not appropriate.
+// Pool's purpose is to cache allocated but unused items for later reuse,
+// relieving pressure on the garbage collector. That is, it makes it easy to
+// build efficient, thread-safe free lists. However, it is not suitable for all
+// free lists.
+//
+// An appropriate use of a Pool is to manage a group of temporary items
+// silently shared among and potentially reused by concurrent independent
+// clients of a package. Pool provides a way to amortize allocation overhead
+// across many clients.
+//
+// An example of good use of a Pool is in the fmt package, which maintains a
+// dynamically-sized store of temporary output buffers. The store scales under
+// load (when many goroutines are actively printing) and shrinks when
+// quiescent.
+//
+// On the other hand, a free list maintained as part of a short-lived object is
+// not a suitable use for a Pool, since the overhead does not amortize well in
+// that scenario. It is more efficient to have such objects implement their own
+// free list.
//
-// This is an experimental type and might not be released.
type Pool struct {
// The following fields are known to runtime.
next *Pool // for use by runtime
また、pin
メソッドのドキュメンテーションコメントも微修正されています。
@@ -173,7 +181,7 @@ func (p *Pool) getSlow() (x interface{}) {\n return\n }\n \n-// pin pins current goroutine to P, disables preemption and returns poolLocal pool for the P.\n+// pin pins the current goroutine to P, disables preemption and returns poolLocal pool for the P.\n // Caller must call runtime_procUnpin() when done with the pool.\n func (p *Pool) pin() *poolLocal {
コアとなるコードの解説
このコミットは、sync.Pool
の実際の動作ロジックを変更するものではなく、そのドキュメンテーションを改善することに焦点を当てています。したがって、Goのランタイムの挙動や sync.Pool
の内部実装(例えば、Get()
や Put()
メソッドの動作)自体には直接的な変更はありません。
しかし、ドキュメンテーションの変更は、sync.Pool
の「使い方」と「意図」に関する重要な情報を提供します。
- GC負荷軽減の強調: 新しいドキュメンテーションは、
sync.Pool
の主要な目的がGCの負荷を軽減することであることを明確にしています。これは、頻繁に割り当てられ、すぐに解放される一時的なオブジェクトに対して特に有効です。 - キャッシュとしての性質:
sync.Pool
に格納されたオブジェクトがGCによっていつでも削除される可能性があるという性質が、より強調されています。これは、sync.Pool
が永続的なストレージではなく、あくまで「キャッシュ」として機能することを意味します。開発者は、プールから取得したオブジェクトが常に利用可能であると仮定すべきではありません。 - 適切なユースケースの具体化:
fmt
パッケージの例を挙げることで、動的にサイズが変化する一時的なバッファのプールなど、sync.Pool
が特に効果を発揮するシナリオが具体的に示されています。これは、多くのゴルーチンが並行して動作し、一時的なリソースを頻繁に必要とするような高負荷なシステムで役立ちます。 - 不適切なユースケースの警告: 短命なオブジェクトの一部としてフリーリストを維持するようなシナリオでは、
sync.Pool
のオーバーヘッドがメリットを上回る可能性があることが警告されています。これは、sync.Pool
が万能なソリューションではないことを示唆し、開発者に慎重な検討を促します。
pin
メソッドのコメントの変更は、単なるタイポ修正("current goroutine to P" から "the current goroutine to P")であり、機能的な意味合いは持ちません。
全体として、このコミットは、sync.Pool
のAPIの安定性と、その設計意図をより正確に伝えることで、Go開発者がこの強力なツールをより効果的かつ安全に使用できるようにするための重要な改善です。
関連リンク
- Go Issue #7167: sync: document Pool better
- Go CL 85880044: sync.Pool: better documentation
参考にした情報源リンク
- Go sync.Pool の目的、良い使い方、悪い使い方に関するウェブ検索結果
- Go sync.Pool Issue 7167 に関するウェブ検索結果
- Go言語のsync.Poolについて - Qiita (一般的な
sync.Pool
の解説として参照) - Goのsync.Poolを理解する - Zenn (一般的な
sync.Pool
の解説として参照) - Goのsync.Poolの正しい使い方と注意点 - Medium (一般的な
sync.Pool
の解説として参照)