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

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

コミット

このコミットは、Go言語のランタイムにNumCPU関数を追加するものです。この関数は、ローカルマシン上のCPUコア数を返します。

  • コミットハッシュ: 6dfdd4c1e34c753fb9c897eee355ee6ca3f007a8
  • 作者: Russ Cox rsc@golang.org
  • コミット日時: 2012年1月9日 月曜日 18:45:59 -0800
  • 変更ファイル:
    • src/pkg/runtime/extern.go
    • src/pkg/runtime/runtime1.goc

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

https://github.com/golang/go/commit/6dfdd4c1e34c753fb9c897eee355ee6ca3f007a8

元コミット内容

runtime: add NumCPU

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5528061

変更の背景

このコミットの背景には、Go言語の並行処理モデルと、それが利用可能なCPUリソースをどのように活用するかという設計思想があります。Go言語はゴルーチン(goroutine)と呼ばれる軽量なスレッドと、それらを効率的にCPUコアにマッピングするスケジューラを備えています。

初期のGoランタイムでは、GOMAXPROCSという環境変数や関数を通じて、同時に実行可能なOSスレッドの最大数を制御していました。このGOMAXPROCSのデフォルト値は、Go 1.5より前は1に設定されており、ユーザーが明示的に設定しない限り、Goプログラムは単一のCPUコアしか利用しませんでした。これは、Goプログラムがデフォルトで並行性を最大限に活用しないことを意味していました。

NumCPU関数の追加は、プログラムが実行されているマシンの物理的または論理的なCPUコア数をプログラム的に取得できるようにすることを目的としています。これにより、開発者はGOMAXPROCSの値を動的に設定する際に、システムのCPU数を考慮に入れることができるようになります。例えば、runtime.GOMAXPROCS(runtime.NumCPU())とすることで、利用可能なすべてのCPUコアをGoスケジューラが利用するように設定することが可能になります。これは、Goプログラムがデフォルトでシステムの並行処理能力を最大限に引き出すための重要なステップでした。

前提知識の解説

Go言語のランタイム

Go言語のランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクション、スケジューラ、メモリ管理、プリミティブな同期メカニズムなどが含まれます。Goのランタイムは、GoプログラムがOSとどのように相互作用するかを抽象化し、ゴルーチンのスケジューリングやメモリ割り当てといった低レベルのタスクを効率的に処理します。

ゴルーチン (Goroutine)

ゴルーチンはGo言語における並行処理の基本単位です。OSスレッドよりもはるかに軽量であり、数百万のゴルーチンを同時に実行することも可能です。ゴルーチンはGoランタイムによって管理され、複数のOSスレッド(M: Machine)に多重化されて実行されます。

GOMAXPROCS

GOMAXPROCSは、Goランタイムが同時に実行できるOSスレッドの最大数を制御する環境変数、またはruntimeパッケージの関数です。この値は、Goスケジューラがゴルーチンをどの程度の並行度で実行するかを決定します。

  • GOMAXPROCS=1の場合、Goプログラムは単一のOSスレッド上でゴルーチンを多重化して実行します。
  • GOMAXPROCS > 1の場合、Goプログラムは指定された数のOSスレッドを起動し、それらのスレッド間でゴルーチンを並行して実行します。

Go 1.5以降では、GOMAXPROCSのデフォルト値は利用可能なCPUコア数に設定されるようになりました。しかし、このコミットが行われた2012年時点では、デフォルト値は1でした。

CPUコア数と並行処理

マルチコアプロセッサの普及により、ソフトウェアは複数のCPUコアを同時に利用することで、処理能力を向上させることができます。Go言語のような並行処理を重視する言語では、利用可能なCPUコア数を正確に把握し、それに応じてスケジューラを調整することが、プログラムのパフォーマンスを最大化するために重要です。NumCPU関数は、この目的のためにシステムのCPUコア数を取得する手段を提供します。

技術的詳細

NumCPU関数の実装は、Goランタイムの内部変数runtime·ncpuの値を返すというシンプルなものです。このruntime·ncpuは、ランタイムの初期化時にシステムから取得されたCPUコア数で設定されます。

コミットでは、以下の2つのファイルが変更されています。

  1. src/pkg/runtime/extern.go: このファイルは、Goランタイムの外部から呼び出される関数や、Goコードからランタイムの内部関数を呼び出すための宣言が含まれています。ここにNumCPU関数の宣言が追加されました。

    // NumCPU returns the number of CPUs on the local machine.
    func NumCPU() int
    

    この宣言は、NumCPUが引数を取らず、int型の値を返すことを示しています。

  2. src/pkg/runtime/runtime1.goc: このファイルは、GoランタイムのC言語で書かれた部分(Go 1.x系ではC言語とGo言語のハイブリッドでランタイムが実装されていました)であり、extern.goで宣言された関数の実際の定義が含まれています。ここにNumCPU関数の実装が追加されました。

    func NumCPU() (ret int32) {
        ret = runtime·ncpu;
    }
    

    ここで、runtime·ncpuというランタイム内部の変数の値がret(戻り値)に代入されています。runtime·ncpuは、ランタイムが起動する際にOSから取得したCPUコア数を保持しています。

この変更により、Goプログラムはruntime.NumCPU()を呼び出すことで、実行環境のCPUコア数を簡単に取得できるようになりました。これは、GOMAXPROCSの値を動的に設定する際の重要な情報源となります。

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

diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index ea36355e66..e86da01732 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -107,6 +107,9 @@ func (f *Func) FileLine(pc uintptr) (file string, line int) {
 // mid returns the current os thread (m) id.
 func mid() uint32
 
+// NumCPU returns the number of CPUs on the local machine.
+func NumCPU() int
+
 // Semacquire waits until *s > 0 and then atomically decrements it.
 // It is intended as a simple sleep primitive for use by the synchronization
 // library and should not be used directly.
diff --git a/src/pkg/runtime/runtime1.goc b/src/pkg/runtime/runtime1.goc
index da2d0c5720..667131c1ee 100644
--- a/src/pkg/runtime/runtime1.goc
+++ b/src/pkg/runtime/runtime1.goc
@@ -8,3 +8,7 @@ package runtime
 func GOMAXPROCS(n int32) (ret int32) {
 	ret = runtime·gomaxprocsfunc(n);
 }
+
+func NumCPU() (ret int32) {
+	ret = runtime·ncpu;
+}

コアとなるコードの解説

src/pkg/runtime/extern.go の変更

  • // NumCPU returns the number of CPUs on the local machine.
    • NumCPU関数の目的を説明するコメントが追加されています。
  • func NumCPU() int
    • runtimeパッケージにNumCPUという新しい関数が宣言されています。この宣言は、Go言語のコードからこの関数を呼び出すためのインターフェースを提供します。戻り値の型はintです。

src/pkg/runtime/runtime1.goc の変更

  • func NumCPU() (ret int32) {
    • NumCPU関数の実際の定義が追加されています。この関数はint32型の戻り値retを持ちます。
  • ret = runtime·ncpu;
    • Goランタイムの内部変数であるruntime·ncpuの値がretに代入されます。runtime·ncpuは、ランタイムが初期化される際にオペレーティングシステムから取得される、システムのCPUコア数を格納しています。
  • }
    • 関数の定義の終わり。

この2つの変更により、Goプログラムはruntime.NumCPU()を呼び出すことで、実行環境のCPUコア数を取得できるようになりました。これは、Goの並行処理をシステムのハードウェアリソースに合わせて最適化するための重要な機能です。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (GitHub): https://github.com/golang/go
  • Go言語のランタイムに関する一般的な情報 (Goのドキュメントやブログ記事)
  • Go言語のGOMAXPROCSに関する情報 (Goのドキュメントやブログ記事)
  • Go言語のコミット履歴 (GitHub)
  • Go言語のコードレビューシステム (Gerrit): https://golang.org/cl/5528061 (元コミット内容に記載されているリンク)