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

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

このコミットは、Go 1.2のリリースノートドキュメント(doc/go1.2.html)に、Goランタイムにおけるスレッド数制限とスタックサイズに関する重要な変更点を追記するものです。具体的には、Goプログラムが使用できるOSスレッドの最大数と、ゴルーチンのスタックの最小サイズおよび最大サイズに関する情報が追加されています。

コミット

  • コミットハッシュ: 0f706d39d4ece12aff931fe2656107864c398e5c
  • Author: Rob Pike r@golang.org
  • Date: Wed Oct 30 08:54:53 2013 -0700

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

https://github.com/golang/go/commit/0f706d39d4ece12aff931fe2656107864c398e5c

元コミット内容

doc/go1.2.html: stack sizes, thread limits

R=golang-dev, minux.ma, adg, rsc
CC=golang-dev
https://golang.org/cl/19600043

変更の背景

Go 1.2では、Goプログラムのパフォーマンスとリソース管理を改善するために、ランタイムの重要な変更が導入されました。このコミットは、これらの変更、特にゴルーチンのスタックサイズとOSスレッドの利用に関する変更を、公式のリリースノートドキュメントに反映させることを目的としています。

具体的な背景としては、以下の問題がありました。

  1. スタックセグメント切り替えによるパフォーマンス問題: Go 1.2以前のゴルーチンの最小スタックサイズ(4KB)では、特にパフォーマンスが重要なセクションで、スタックの拡張・縮小に伴う「スタックセグメント切り替え」が頻繁に発生し、これがオーバーヘッドとなってパフォーマンスを低下させていました。
  2. 暴走する再帰によるメモリ枯渇: ゴルーチンが無限再帰に陥った場合、スタックが際限なく拡張され、システム全体のメモリを枯渇させる可能性がありました。
  3. リソース枯渇の回避: 特定の環境下で、Goプログラムが過剰な数のOSスレッドを生成し、システムリソースを枯渇させる可能性がありました。

これらの問題を解決するため、Go 1.2ではランタイムレベルでの改善が行われ、その内容をユーザーに伝えるためにドキュメントの更新が必要とされました。

前提知識の解説

このコミットの理解には、以下のGo言語の概念とランタイムの動作に関する知識が役立ちます。

  • ゴルーチン (Goroutine): Go言語における軽量な並行処理の単位です。OSスレッドよりもはるかに軽量で、数千、数万のゴルーチンを同時に実行できます。Goランタイムが複数のゴルーチンを少数のOSスレッドに多重化(multiplex)して実行します。
  • OSスレッド (Operating System Thread): オペレーティングシステムが管理する実行の単位です。CPUコア上で実際にコードを実行するのはOSスレッドです。Goランタイムは、ゴルーチンをOSスレッドにマッピングして実行します。
  • スタック (Stack): プログラムの実行中に、関数呼び出しの引数、ローカル変数、戻りアドレスなどが一時的に格納されるメモリ領域です。ゴルーチンごとに独自のスタックを持ちます。
  • スタックセグメント切り替え (Stack-segment switching): Goの初期のバージョンでは、ゴルーチンのスタックは必要に応じて動的に拡張・縮小される「セグメントスタック」という方式を採用していました。スタックが現在のセグメントの限界に達すると、より大きな新しいセグメントに切り替える必要があり、この切り替え処理がオーバーヘッドとなることがありました。
  • runtime/debug パッケージ: Goのランタイムのデバッグ情報や、ランタイムの動作を制御するための関数を提供するパッケージです。このコミットで言及されているSetMaxThreadsSetMaxStack関数が含まれます。
  • GOMAXPROCS: 環境変数またはruntime.GOMAXPROCS関数で設定できる値で、同時にユーザーレベルのGoコードを実行できるOSスレッドの最大数を制御します。これは、システムコールでブロックされているスレッドの数とは異なります。

技術的詳細

Go 1.2におけるスレッド数制限とスタックサイズの変更は、Goプログラムの安定性とパフォーマンスを向上させるための重要な改善でした。

スレッド数制限 (SetMaxThreads)

  • 導入: Go 1.2では、単一のGoプログラムがアドレス空間内に持つことができるOSスレッドの総数に、設定可能な制限が導入されました。
  • デフォルト値: デフォルトの制限は10,000スレッドです。
  • 目的: この制限は、特定の環境下でのリソース枯渇問題を回避するために設けられました。
  • ゴルーチンとの関係: この制限はゴルーチンの数に直接的な影響を与えません。ゴルーチンはOSスレッドに多重化されるため、この制限は主にシステムコールで同時にブロックされる可能性のあるスレッドの数を制限します。実際には、この制限に達することは稀であるとされています。
  • 制御関数: runtime/debugパッケージのSetMaxThreads関数を使用して、このスレッド数制限を制御できます。
  • 影響と対応: プログラムがこの制限に達して異常終了する場合、SetMaxThreadsを呼び出してより高い制限を設定することで対応できます。しかし、より良い解決策は、カーネルリソースの消費を減らすために、プログラムをリファクタリングして必要なスレッド数を減らすことです。

スタックサイズ (SetMaxStack, 最小スタックサイズ)

  • 最小スタックサイズの増加: Go 1.2では、ゴルーチンが作成される際の最小スタックサイズが、従来の4KBから8KBに引き上げられました。
    • 理由: 以前のサイズでは、パフォーマンスが重要なセクションで高コストなスタックセグメント切り替えが頻繁に発生し、多くのプログラムがパフォーマンス問題に苦しんでいました。新しい8KBという値は、経験的なテストに基づいて決定されました。
    • 影響: 最小スタックサイズの増加は、多数のゴルーチンを持つプログラムでメモリ使用量が増加する可能性があります。この時点では直接的な回避策はありませんでしたが、将来のリリースで新しいスタック管理技術(Go 1.4で導入された連続スタックなど)によってこの問題が改善されることが示唆されていました。
  • 最大スタックサイズ (SetMaxStack):
    • 導入: Go 1.2では、単一のゴルーチンのスタックの「最大」サイズを制御するruntime/debugパッケージのSetMaxStack関数が導入されました。
    • デフォルト値: デフォルトの最大スタックサイズは、64ビットシステムで1GB、32ビットシステムで250MBです。
    • 目的: Go 1.2以前は、暴走する再帰によってマシン上のすべてのメモリが容易に消費されてしまう可能性がありました。この最大スタックサイズの設定により、そのようなメモリ枯渇を防ぐことができます。

これらの変更は、Goプログラムの堅牢性と効率性を高める上で重要なステップであり、特に大規模な並行処理を行うアプリケーションにおいて、より予測可能で安定した動作を保証するのに役立ちました。

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

このコミットは、doc/go1.2.htmlという単一のファイルを変更しています。

--- a/doc/go1.2.html
+++ b/doc/go1.2.html
@@ -137,6 +137,55 @@ This means that any loop that includes a (non-inlined) function call can
 be pre-empted, allowing other goroutines to run on the same thread.
 </p>
 
+<h3 id=\"thread_limit\">Limit on the number of threads</h3>
+
+<p>
+Go 1.2 introduces a configurable limit (default 10,000) to the total number of threads
+a single program may have in its address space, to avoid resource starvation
+issues in some environments.
+Note that goroutines are multiplexed onto threads so this limit does not directly
+limit the number of goroutines, only the number that may be simultaneously blocked
+in a system call.
+In practice, the limit is hard to reach.
+</p>
+
+<p>
+The new <a href=\"/pkg/runtime/debug/#SetMaxThreads\"><code>SetMaxThreads</code></a> function in the
+<a href=\"/pkg/runtime/debug/\"><code>runtime/debug</code></a> package controls the thread count limit.
+</p>
+
+<p>
+<em>Updating</em>:
+Few functions will be affected by the limit, but if a program dies because it hits the
+limit, it could be modified to call <code>SetMaxThreads</code> to set a higher count.
+Even better would be to refactor the program to need fewer threads, reducing consumption
+of kernel resources.
+</p>
+
+<h3 id=\"stack_size\">Stack size</h3>
+
+<p>
+In Go 1.2, the minimum size of the stack when a goroutine is created has been lifted from 4KB to 8KB.
+Many programs were suffering performance problems with the old size, which had a tendency
+to introduce expensive stack-segment switching in performance-critical sections.
+The new number was determined by empirical testing.
+</p>
+
+<p>
+At the other end, the new function <a href=\"/pkg/runtime/debug/#SetMaxStack\"><code>SetMaxStack</code></a>
+in the <a href=\"/pkg/runtime/debug\"><code>runtime/debug</code></a> package controls
+the <em>maximum</em> size of a single goroutine\'s stack.
+The default is 1GB on 64-bit systems and 250MB on 32-bit systems.
+Before Go 1.2, it was too easy for a runaway recursion to consume all the memory on a machine.
+</p>
+
+<p>
+<em>Updating</em>:
+The increased minimum stack size may cause programs with many goroutines to use
+more memory. There is no workaround, but future plans for future releases
+include new stack management technology that should address the problem better.
+</p>
+
 <h3 id=\"cgo_and_cpp\">Cgo and C++</h3>
 
 <p>

コアとなるコードの解説

このコミットは、Go 1.2のリリースノートに以下の2つの新しいセクションを追加しています。

  1. Limit on the number of threads (スレッド数制限):

    • Go 1.2で導入された、単一プログラムが持つことができるOSスレッドの総数に対する設定可能な制限(デフォルト10,000)について説明しています。
    • この制限がリソース枯渇を防ぐためのものであること、そしてゴルーチンの数ではなく、システムコールで同時にブロックされるスレッドの数を制限するものであることを強調しています。
    • runtime/debugパッケージのSetMaxThreads関数を使ってこの制限を制御できることを示しています。
    • 「Updating」セクションでは、プログラムがこの制限に達した場合の対処法(SetMaxThreadsで制限を上げるか、スレッド数を減らすようにリファクタリングする)についてアドバイスしています。
  2. Stack size (スタックサイズ):

    • Go 1.2でゴルーチン作成時の最小スタックサイズが4KBから8KBに引き上げられたことを説明しています。これは、以前のサイズで発生していた高コストなスタックセグメント切り替えによるパフォーマンス問題を解決するためです。
    • runtime/debugパッケージのSetMaxStack関数を使って、単一ゴルーチンのスタックの「最大」サイズを制御できることを説明しています。デフォルト値は64ビットシステムで1GB、32ビットシステムで250MBです。これは、暴走する再帰がシステムメモリを枯渇させるのを防ぐためのものです。
    • 「Updating」セクションでは、最小スタックサイズの増加が多数のゴルーチンを持つプログラムのメモリ使用量を増やす可能性があること、そして将来のリリースで新しいスタック管理技術(Go 1.4で導入された連続スタックなど)がこの問題に対処する予定であることを述べています。

これらの追加は、Go 1.2の重要なランタイム変更をユーザーに明確に伝え、開発者がこれらの変更を理解し、必要に応じてプログラムを調整できるようにするためのものです。

関連リンク

参考にした情報源リンク