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

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

このコミットは、Go言語の標準ライブラリ sync パッケージ内のベンチマークテストにおいて、並行処理のテスト方法を改善するものです。具体的には、手動でゴルーチンを管理し、runtime.Gosched()atomic パッケージを用いていた既存のベンチマークコードを、testing パッケージが提供する b.RunParallel 関数を使用するように変更しています。これにより、ベンチマークの記述が簡潔になり、より正確で効率的な並行ベンチマークが可能になります。

コミット

commit ec0c9f270e8c09b00df5e45d87cfa4c85df63271
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Tue Feb 25 14:39:12 2014 +0400

    sync: use RunParallel in benchmarks
    
    LGTM=bradfitz
    R=golang-codereviews, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/68050043

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

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

元コミット内容

このコミットの元のメッセージは以下の通りです。

sync: use RunParallel in benchmarks

LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/68050043

これは、sync パッケージのベンチマークで RunParallel を使用するように変更したことを簡潔に示しています。

変更の背景

Go言語のベンチマークは、testing パッケージの Benchmark 関数によって実行されます。以前のGoのバージョンでは、並行処理のベンチマークを行う際に、開発者が手動で複数のゴルーチンを起動し、runtime.GOMAXPROCSruntime.Gosched()sync/atomic パッケージなどを用いて並行性を制御する必要がありました。これは、ベンチマークコードを複雑にし、正確な測定を困難にする可能性がありました。

testing.B.RunParallel 関数は、Go 1.2で導入された機能であり、並行ベンチマークをより簡単かつ正確に記述するためのものです。この関数は、GOMAXPROCS の値に基づいて自動的に適切な数のゴルーチンを起動し、各ゴルーチンにベンチマークのイテレーションを均等に分散させます。これにより、手動でのゴルーチン管理や競合状態のシミュレーションが不要になり、ベンチマークの信頼性と保守性が向上します。

このコミットは、sync パッケージ内の Mutex, Once, Pool, runtime_sema, RWMutex, WaitGroup といった並行プリミティブのベンチマークを、この新しい b.RunParallel メカニズムに移行することを目的としています。これにより、これらの重要な並行プリミティブの性能測定がより堅牢になります。

前提知識の解説

Go言語のベンチマーク

Go言語では、testing パッケージを使用してベンチマークテストを記述します。ベンチマーク関数は BenchmarkXxx(*testing.B) というシグネチャを持ち、go test -bench=. コマンドで実行されます。*testing.B 型の b オブジェクトは、ベンチマークの実行回数 (b.N) や、並行ベンチマークのための b.RunParallel などのメソッドを提供します。

testing.B.RunParallel

b.RunParallel は、並行ベンチマークを実行するためのメソッドです。引数として func(pb *testing.PB) 型の関数を受け取ります。この関数は、b.RunParallel によって起動された各ゴルーチンで実行されます。*testing.PB 型の pb オブジェクトは、pb.Next() メソッドを提供し、ベンチマークの各イテレーションが完了したことを通知します。pb.Next() は、すべてのイテレーションが完了すると false を返します。

b.RunParallel は、runtime.GOMAXPROCS の値に基づいて、自動的に適切な数のゴルーチンを起動します。これにより、手動でゴルーチンを管理する手間が省け、また、GOMAXPROCS の設定変更にも自動的に対応できるため、より現実的な並行性能を測定できます。

sync パッケージ

sync パッケージは、Go言語における基本的な並行処理のプリミティブを提供します。このコミットで変更されている主なコンポーネントは以下の通りです。

  • sync.Mutex: 排他ロック。複数のゴルーチンが共有リソースに同時にアクセスするのを防ぎます。
  • sync.Once: ある処理が一度だけ実行されることを保証します。初期化処理などで使用されます。
  • sync.Pool: 一時的なオブジェクトのプール。オブジェクトの再利用を促進し、ガベージコレクションの負荷を軽減します。
  • sync.RWMutex: 読み書きロック。複数の読み取りは同時に許可しますが、書き込みは排他的に行われます。
  • sync.WaitGroup: 複数のゴルーチンの完了を待機するためのメカニズム。

runtime.Gosched()sync/atomic

変更前のベンチマークコードでは、手動でゴルーチンを管理するために以下の関数やパッケージが使用されていました。

  • runtime.Gosched(): 現在のゴルーチンを一時停止し、他のゴルーチンにCPUを譲ります。これにより、明示的にコンテキストスイッチを発生させ、並行性をシミュレートしていました。
  • sync/atomic: アトミック操作を提供します。複数のゴルーチンから共有されるカウンタなどを安全に更新するために使用されていました。例えば、atomic.AddInt32 は、ベンチマークの総イテレーション数を複数のゴルーチンで共有し、各ゴルーチンが処理したイテレーション数を減算するために使われていました。

これらの手動での並行性制御は、b.RunParallel の導入により不要になります。

技術的詳細

このコミットの主要な変更点は、sync パッケージ内の各ベンチマーク関数から、手動でゴルーチンを起動し、runtime.Gosched()sync/atomic を使用してイテレーションを制御するロジックを削除し、代わりに b.RunParallel を呼び出すように変更したことです。

変更前は、以下のようなパターンが頻繁に見られました。

  1. runtime.GOMAXPROCS(-1) を呼び出して、利用可能なCPUコア数を取得。
  2. そのコア数に基づいて、またはそれよりも多くのゴルーチンを go func() で起動。
  3. 各ゴルーチン内で、atomic.AddInt32(&N, -1) のようなアトミック操作で全体のイテレーション数を管理し、N が0になるまでループ。
  4. ループ内で runtime.Gosched() を呼び出し、他のゴルーチンに実行を譲る。
  5. 結果をチャネル (c := make(chan bool, procs)) で収集し、すべてのゴルーチンの完了を待機。

このコミットでは、上記の複雑なロジックが b.RunParallel の呼び出しに置き換えられています。b.RunParallel は、内部でこれらの並行処理の管理を自動的に行います。

例えば、BenchmarkMutexUncontended の変更を見てみましょう。

変更前:

func BenchmarkMutexUncontended(b *testing.B) {
	type PaddedMutex struct {
		Mutex
		pad [128]uint8
	}
	const CallsPerSched = 1000
	procs := runtime.GOMAXPROCS(-1)
	N := int32(b.N / CallsPerSched)
	c := make(chan bool, procs)
	for p := 0; p < procs; p++ {
		go func() {
			var mu PaddedMutex
			for atomic.AddInt32(&N, -1) >= 0 {
				runtime.Gosched()
				for g := 0; g < CallsPerSched; g++ {
					mu.Lock()
					mu.Unlock()
				}
			}
			c <- true
		}()
	}
	for p := 0; p < procs; p++ {
		<-c
	}
}

変更後:

func BenchmarkMutexUncontended(b *testing.B) {
	type PaddedMutex struct {
		Mutex
		pad [128]uint8
	}
	b.RunParallel(func(pb *testing.PB) {
		var mu PaddedMutex
		for pb.Next() {
			mu.Lock()
			mu.Unlock()
		}
	})
}

この変更により、コードが大幅に簡潔になり、runtime.Gosched()atomic パッケージへの依存がなくなっています。b.RunParallel が自動的に複数のゴルーチンを起動し、pb.Next() が各ゴルーチンに次のイテレーションを実行するように指示します。

また、benchmarkMutex のように、slack (ゴルーチンの数を増やす) オプションを持つベンチマークでは、b.SetParallelism(10) のような呼び出しが追加され、RunParallel が起動するゴルーチンの数を制御できるようになっています。これは、特定のシナリオでの並行性をシミュレートするために使用されます。

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

このコミットでは、以下のファイルのベンチマーク関数が変更されています。

  • src/pkg/sync/mutex_test.go
  • src/pkg/sync/once_test.go
  • src/pkg/sync/pool_test.go
  • src/pkg/sync/runtime_sema_test.go
  • src/pkg/sync/rwmutex_test.go
  • src/pkg/sync/waitgroup_test.go

各ファイルにおいて、BenchmarkXxx という名前の関数内で、手動でゴルーチンを起動し、runtime.Gosched()sync/atomic を使用してイテレーションを制御していた部分が、b.RunParallel の呼び出しに置き換えられています。

具体的な変更例は以下の通りです。

src/pkg/sync/mutex_test.goBenchmarkMutexUncontended:

  • runtime.GOMAXPROCS(-1) の呼び出しを削除。
  • atomic.AddInt32(&N, -1) を使用したイテレーション管理ループを削除。
  • runtime.Gosched() の呼び出しを削除。
  • チャネル (c) を使用したゴルーチン間の同期を削除。
  • 代わりに b.RunParallel(func(pb *testing.PB) { ... }) を使用し、ループ条件を for pb.Next() に変更。

src/pkg/sync/once_test.goBenchmarkOnce:

  • 同様に、手動のゴルーチン管理と atomic 操作を削除し、b.RunParallel に置き換え。

src/pkg/sync/pool_test.goBenchmarkPool および BenchmarkPoolOverlflow:

  • WaitGroupatomic を使用した並行処理の制御を削除し、b.RunParallel に置き換え。

src/pkg/sync/runtime_sema_test.goBenchmarkSemaUncontended および benchmarkSema:

  • 手動のゴルーチン管理と atomic 操作を削除し、b.RunParallel に置き換え。
  • benchmarkSema では、block シナリオでの初期セマフォ取得ロジックも b.RunParallel の外に移動し、done チャネルで同期する形に変更。

src/pkg/sync/rwmutex_test.goBenchmarkRWMutexUncontended および benchmarkRWMutex:

  • 手動のゴルーチン管理と atomic 操作を削除し、b.RunParallel に置き換え。

src/pkg/sync/waitgroup_test.goBenchmarkWaitGroupUncontended, benchmarkWaitGroupAddDone, benchmarkWaitGroupWait:

  • 手動のゴルーチン管理と atomic 操作を削除し、b.RunParallel に置き換え。

全体として、この変更は、Goのベンチマークフレームワークの進化に合わせて、sync パッケージのベンチマークコードを現代化し、より堅牢で保守しやすいものにすることを目的としています。

コアとなるコードの解説

このコミットのコアとなる変更は、Goのベンチマークにおける並行処理の記述方法のパラダイムシフトを示しています。

変更前のアプローチ(手動ゴルーチン管理)の問題点:

  1. 複雑性: 複数のゴルーチンを起動し、runtime.Gosched() でコンテキストスイッチを促し、atomic 操作でイテレーション数を同期させるなど、ベンチマークコード自体が複雑になりがちでした。これは、ベンチマークの意図を理解し、保守するのを困難にしていました。
  2. 正確性の課題: runtime.Gosched() の呼び出し頻度や、GOMAXPROCS の設定がベンチマーク結果に与える影響を正確に制御するのが難しく、再現性や信頼性に課題が生じる可能性がありました。特に、runtime.Gosched() はスケジューラのヒントであり、必ずしも期待通りに動作するとは限りません。
  3. スケーラビリティ: GOMAXPROCS の値が変わるたびに、手動でゴルーチン数を調整する必要があるなど、環境への適応性が低いという問題がありました。

変更後のアプローチ(b.RunParallel の利用)の利点:

  1. 簡潔性: b.RunParallel を使用することで、並行ベンチマークのロジックが大幅に簡素化されます。開発者は、各ゴルーチンが実行すべき単一のイテレーションの処理に集中できます。
  2. 自動的な並行性管理: b.RunParallel は、GOMAXPROCS の設定に基づいて最適な数のゴルーチンを自動的に起動し、ベンチマークのイテレーションをそれらのゴルーチンに均等に分散させます。これにより、手動での調整が不要になり、異なる環境でも一貫した結果が得られやすくなります。
  3. 正確性と信頼性: b.RunParallel は、Goのテストフレームワークによって最適化されており、より正確で信頼性の高い並行ベンチマーク測定を可能にします。内部的には、各ゴルーチンが pb.Next() を呼び出すことで、テストフレームワークがイテレーションの進行を追跡し、全体のベンチマーク時間を正確に測定します。
  4. 保守性: コードが簡潔になることで、ベンチマークの保守が容易になります。

このコミットは、Goのベンチマークフレームワークが成熟し、より高度な並行ベンチマーク機能を提供できるようになったことを示しています。sync パッケージのような低レベルの並行プリミティブのベンチマークにおいて、この変更は特に重要であり、これらのプリミティブの性能特性をより正確に評価するための基盤を強化します。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコード (特に src/testing/benchmark.gosrc/pkg/sync 以下のテストファイル)
  • Go言語のコミット履歴とコードレビューコメント
  • testing.B.RunParallel に関する技術記事や解説(一般的なGoのベンチマークに関する情報)
  • Go言語の sync/atomic パッケージのドキュメント: https://pkg.go.dev/sync/atomic
  • Go言語の runtime パッケージのドキュメント: https://pkg.go.dev/runtime

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

このコミットは、Go言語の標準ライブラリ sync パッケージ内のベンチマークテストにおいて、並行処理のテスト方法を改善するものです。具体的には、手動でゴルーチンを管理し、runtime.Gosched()atomic パッケージを用いていた既存のベンチマークコードを、testing パッケージが提供する b.RunParallel 関数を使用するように変更しています。これにより、ベンチマークの記述が簡潔になり、より正確で効率的な並行ベンチマークが可能になります。

コミット

commit ec0c9f270e8c09b00df5e45d87cfa4c85df63271
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Tue Feb 25 14:39:12 2014 +0400

    sync: use RunParallel in benchmarks
    
    LGTM=bradfitz
    R=golang-codereviews, bradfitz
    CC=golang-codereviews
    https://golang.org/cl/68050043

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

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

元コミット内容

このコミットの元のメッセージは以下の通りです。

sync: use RunParallel in benchmarks

LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/68050043

これは、sync パッケージのベンチマークで RunParallel を使用するように変更したことを簡潔に示しています。

変更の背景

Go言語のベンチマークは、testing パッケージの Benchmark 関数によって実行されます。以前のGoのバージョンでは、並行処理のベンチマークを行う際に、開発者が手動で複数のゴルーチンを起動し、runtime.GOMAXPROCSruntime.Gosched()sync/atomic パッケージなどを用いて並行性を制御する必要がありました。これは、ベンチマークコードを複雑にし、正確な測定を困難にする可能性がありました。

testing.B.RunParallel 関数は、Go 1.2で導入された機能であり、並行ベンチマークをより簡単かつ正確に記述するためのものです。この関数は、GOMAXPROCS の値に基づいて自動的に適切な数のゴルーチンを起動し、各ゴルーチンにベンチマークのイテレーションを均等に分散させます。これにより、手動でのゴルーチン管理や競合状態のシミュレーションが不要になり、ベンチマークの信頼性と保守性が向上します。

このコミットは、sync パッケージ内の Mutex, Once, Pool, runtime_sema, RWMutex, WaitGroup といった並行プリミティブのベンチマークを、この新しい b.RunParallel メカニズムに移行することを目的としています。これにより、これらの重要な並行プリミティブの性能測定がより堅牢になります。

前提知識の解説

Go言語のベンチマーク

Go言語では、testing パッケージを使用してベンチマークテストを記述します。ベンチマーク関数は BenchmarkXxx(*testing.B) というシグネチャを持ち、go test -bench=. コマンドで実行されます。*testing.B 型の b オブジェクトは、ベンチマークの実行回数 (b.N) や、並行ベンチマークのための b.RunParallel などのメソッドを提供します。

testing.B.RunParallel

b.RunParallel は、並行ベンチマークを実行するためのメソッドです。引数として func(pb *testing.PB) 型の関数を受け取ります。この関数は、b.RunParallel によって起動された各ゴルーチンで実行されます。*testing.PB 型の pb オブジェクトは、pb.Next() メソッドを提供し、ベンチマークの各イテレーションが完了したことを通知します。pb.Next() は、すべてのイテレーションが完了すると false を返します。

b.RunParallel は、runtime.GOMAXPROCS の値に基づいて、自動的に適切な数のゴルーチンを起動します。これにより、手動でゴルーチンを管理する手間が省け、また、GOMAXPROCS の設定変更にも自動的に対応できるため、より現実的な並行性能を測定できます。

sync パッケージ

sync パッケージは、Go言語における基本的な並行処理のプリミティブを提供します。このコミットで変更されている主なコンポーネントは以下の通りです。

  • sync.Mutex: 排他ロック。複数のゴルーチンが共有リソースに同時にアクセスするのを防ぎます。
  • sync.Once: ある処理が一度だけ実行されることを保証します。初期化処理などで使用されます。
  • sync.Pool: 一時的なオブジェクトのプール。オブジェクトの再利用を促進し、ガベージコレクションの負荷を軽減します。
  • sync.RWMutex: 読み書きロック。複数の読み取りは同時に許可しますが、書き込みは排他的に行われます。
  • sync.WaitGroup: 複数のゴルーチンの完了を待機するためのメカニズム。

runtime.Gosched()sync/atomic

変更前のベンチマークコードでは、手動でゴルーチンを管理するために以下の関数やパッケージが使用されていました。

  • runtime.Gosched(): 現在のゴルーチンを一時停止し、他のゴルーチンにCPUを譲ります。これにより、明示的にコンテキストスイッチを発生させ、並行性をシミュレートしていました。
  • sync/atomic: アトミック操作を提供します。複数のゴルーチンから共有されるカウンタなどを安全に更新するために使用されていました。例えば、atomic.AddInt32 は、ベンチマークの総イテレーション数を複数のゴルーチンで共有し、各ゴルーチンが処理したイテレーション数を減算するために使われていました。

これらの手動での並行性制御は、b.RunParallel の導入により不要になります。

技術的詳細

このコミットの主要な変更点は、sync パッケージ内の各ベンチマーク関数から、手動でゴルーチンを起動し、runtime.Gosched()sync/atomic を使用してイテレーションを制御するロジックを削除し、代わりに b.RunParallel を呼び出すように変更したことです。

変更前は、以下のようなパターンが頻繁に見られました。

  1. runtime.GOMAXPROCS(-1) を呼び出して、利用可能なCPUコア数を取得。
  2. そのコア数に基づいて、またはそれよりも多くのゴルーチンを go func() で起動。
  3. 各ゴルーチン内で、atomic.AddInt32(&N, -1) のようなアトミック操作で全体のイテレーション数を管理し、N が0になるまでループ。
  4. ループ内で runtime.Gosched() を呼び出し、他のゴルーチンに実行を譲る。
  5. 結果をチャネル (c := make(chan bool, procs)) で収集し、すべてのゴルーチンの完了を待機。

このコミットでは、上記の複雑なロジックが b.RunParallel の呼び出しに置き換えられています。b.RunParallel は、内部でこれらの並行処理の管理を自動的に行います。

例えば、BenchmarkMutexUncontended の変更を見てみましょう。

変更前:

func BenchmarkMutexUncontended(b *testing.B) {
	type PaddedMutex struct {
		Mutex
		pad [128]uint8
	}
	const CallsPerSched = 1000
	procs := runtime.GOMAXPROCS(-1)
	N := int32(b.N / CallsPerSched)
	c := make(chan bool, procs)
	for p := 0; p < procs; p++ {
		go func() {
			var mu PaddedMutex
			for atomic.AddInt32(&N, -1) >= 0 {
				runtime.Gosched()
				for g := 0; g < CallsPerSched; g++ {
					mu.Lock()
					mu.Unlock()
				}
			}
			c <- true
		}()
	}
	for p := 0; p < procs; p++ {
		<-c
	}
}

変更後:

func BenchmarkMutexUncontended(b *testing.B) {
	type PaddedMutex struct {
		Mutex
		pad [128]uint8
	}
	b.RunParallel(func(pb *testing.PB) {
		var mu PaddedMutex
		for pb.Next() {
			mu.Lock()
			mu.Unlock()
		}
	})
}

この変更により、コードが大幅に簡潔になり、runtime.Gosched()atomic パッケージへの依存がなくなっています。b.RunParallel が自動的に複数のゴルーチンを起動し、pb.Next() が各ゴルーチンに次のイテレーションを実行するように指示します。

また、benchmarkMutex のように、slack (ゴルーチンの数を増やす) オプションを持つベンチマークでは、b.SetParallelism(10) のような呼び出しが追加され、RunParallel が起動するゴルーチンの数を制御できるようになっています。これは、特定のシナリオでの並行性をシミュレートするために使用されます。

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

このコミットでは、以下のファイルのベンチマーク関数が変更されています。

  • src/pkg/sync/mutex_test.go
  • src/pkg/sync/once_test.go
  • src/pkg/sync/pool_test.go
  • src/pkg/sync/runtime_sema_test.go
  • src/pkg/sync/rwmutex_test.go
  • src/pkg/sync/waitgroup_test.go

各ファイルにおいて、BenchmarkXxx という名前の関数内で、手動でゴルーチンを起動し、runtime.Gosched()sync/atomic を使用してイテレーションを制御していた部分が、b.RunParallel の呼び出しに置き換えられています。

具体的な変更例は以下の通りです。

src/pkg/sync/mutex_test.goBenchmarkMutexUncontended:

  • runtime.GOMAXPROCS(-1) の呼び出しを削除。
  • atomic.AddInt32(&N, -1) を使用したイテレーション管理ループを削除。
  • runtime.Gosched() の呼び出しを削除。
  • チャネル (c) を使用したゴルーチン間の同期を削除。
  • 代わりに b.RunParallel(func(pb *testing.PB) { ... }) を使用し、ループ条件を for pb.Next() に変更。

src/pkg/sync/once_test.goBenchmarkOnce:

  • 同様に、手動のゴルーチン管理と atomic 操作を削除し、b.RunParallel に置き換え。

src/pkg/sync/pool_test.goBenchmarkPool および BenchmarkPoolOverlflow:

  • WaitGroupatomic を使用した並行処理の制御を削除し、b.RunParallel に置き換え。

src/pkg/sync/runtime_sema_test.goBenchmarkSemaUncontended および benchmarkSema:

  • 手動のゴルーチン管理と atomic 操作を削除し、b.RunParallel に置き換え。
  • benchmarkSema では、block シナリオでの初期セマフォ取得ロジックも b.RunParallel の外に移動し、done チャネルで同期する形に変更。

src/pkg/sync/rwmutex_test.goBenchmarkRWMutexUncontended および benchmarkRWMutex:

  • 手動のゴルーチン管理と atomic 操作を削除し、b.RunParallel に置き換え。

src/pkg/sync/waitgroup_test.goBenchmarkWaitGroupUncontended, benchmarkWaitGroupAddDone, benchmarkWaitGroupWait:

  • 手動のゴルーチン管理と atomic 操作を削除し、b.RunParallel に置き換え。

全体として、この変更は、Goのベンチマークフレームワークの進化に合わせて、sync パッケージのベンチマークコードを現代化し、より堅牢で保守しやすいものにすることを目的としています。

コアとなるコードの解説

このコミットのコアとなる変更は、Goのベンチマークにおける並行処理の記述方法のパラダイムシフトを示しています。

変更前のアプローチ(手動ゴルーチン管理)の問題点:

  1. 複雑性: 複数のゴルーチンを起動し、runtime.Gosched() でコンテキストスイッチを促し、atomic 操作でイテレーション数を同期させるなど、ベンチマークコード自体が複雑になりがちでした。これは、ベンチマークの意図を理解し、保守するのを困難にしていました。
  2. 正確性の課題: runtime.Gosched() の呼び出し頻度や、GOMAXPROCS の設定がベンチマーク結果に与える影響を正確に制御するのが難しく、再現性や信頼性に課題が生じる可能性がありました。特に、runtime.Gosched() はスケジューラのヒントであり、必ずしも期待通りに動作するとは限りません。
  3. スケーラビリティ: GOMAXPROCS の値が変わるたびに、手動でゴルーチン数を調整する必要があるなど、環境への適応性が低いという問題がありました。

変更後のアプローチ(b.RunParallel の利用)の利点:

  1. 簡潔性: b.RunParallel を使用することで、並行ベンチマークのロジックが大幅に簡素化されます。開発者は、各ゴルーチンが実行すべき単一のイテレーションの処理に集中できます。
  2. 自動的な並行性管理: b.RunParallel は、GOMAXPROCS の設定に基づいて最適な数のゴルーチンを自動的に起動し、ベンチマークのイテレーションをそれらのゴルーチンに均等に分散させます。これにより、手動での調整が不要になり、異なる環境でも一貫した結果が得られやすくなります。
  3. 正確性と信頼性: b.RunParallel は、Goのテストフレームワークによって最適化されており、より正確で信頼性の高い並行ベンチマーク測定を可能にします。内部的には、各ゴルーチンが pb.Next() を呼び出すことで、テストフレームワークがイテレーションの進行を追跡し、全体のベンチマーク時間を正確に測定します。
  4. 保守性: コードが簡潔になることで、ベンチマークの保守が容易になります。

このコミットは、Goのベンチマークフレームワークが成熟し、より高度な並行ベンチマーク機能を提供できるようになったことを示しています。sync パッケージのような低レベルの並行プリミティブのベンチマークにおいて、この変更は特に重要であり、これらのプリミティブの性能特性をより正確に評価するための基盤を強化します。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコード (特に src/testing/benchmark.gosrc/pkg/sync 以下のテストファイル)
  • Go言語のコミット履歴とコードレビューコメント
  • testing.B.RunParallel に関する技術記事や解説(一般的なGoのベンチマークに関する情報)
  • Go言語の sync/atomic パッケージのドキュメント: https://pkg.go.dev/sync/atomic
  • Go言語の runtime パッケージのドキュメント: https://pkg.go.dev/runtime