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

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

このコミットは、Go言語のネットワークパッケージ(net)において、NetBSDオペレーティングシステム上でのランタイム統合型ネットワークポーラー(runtime-integrated network pollster)を有効にするための変更です。具体的には、NetBSDがGoランタイムのI/Oスケジューラと連携して、より効率的なネットワークI/O処理を行えるようにビルドタグが調整されています。

コミット

commit 96d7997f0355d165e953f15e10d626556b08e46c
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Sat Aug 17 13:40:14 2013 +0900

    net: enable runtime-integrated network pollster on netbsd
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/13080043

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

https://github.com/golang/go/commit/96d7997f0355d165e953f15e10d626556b08e46c

元コミット内容

net: enable runtime-integrated network pollster on netbsd

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

変更の背景

Go言語のランタイムは、効率的な並行処理を実現するために、独自のゴルーチン(goroutine)スケジューラとネットワークI/Oスケジューラを持っています。ネットワークI/Oは通常ブロッキング操作ですが、Goランタイムはこれをノンブロッキングに変換し、I/Oが完了するまでゴルーチンを一時停止させ、他のゴルーチンを実行することで、高い並行性を実現しています。この仕組みの核となるのが「ネットワークポーラー(network poller)」です。

Goのネットワークポーラーは、オペレーティングシステム(OS)が提供する効率的なI/O多重化メカニズム(例: Linuxのepoll、macOS/FreeBSDのkqueue、WindowsのI/O完了ポート)を利用して、多数のネットワーク接続を効率的に監視します。これにより、I/O準備ができたファイルディスクリプタ(FD)を検出し、対応するゴルーチンを再開させることができます。

このコミット以前、NetBSDはGoのランタイム統合型ネットワークポーラーの対象外でした。これは、NetBSD上でのGoプログラムのネットワークI/Oが、他のOSに比べて効率が悪い可能性があったことを意味します。具体的には、GoランタイムがOSネイティブの効率的なI/O多重化メカニズムを直接利用せず、より汎用的な(しかし効率の劣る)方法でネットワークI/Oを処理していた可能性があります。

この変更の背景には、NetBSD上でのGoアプリケーションのネットワークパフォーマンスを向上させるという目的があります。NetBSDもkqueue/keventシステムコールをサポートしており、これをGoランタイムのネットワークポーラーに統合することで、他のBSD系OS(FreeBSD、OpenBSD、Darwin)と同様に、NetBSD上でもGoのネットワークI/Oが効率的に処理されるようになります。

前提知識の解説

1. Go言語の並行処理とスケジューラ

Go言語は、軽量なスレッドである「ゴルーチン(goroutine)」と、それらを効率的にOSスレッドにマッピングする「Goスケジューラ」によって並行処理を実現します。ゴルーチンは数KB程度のスタックしか持たず、数百万個を同時に生成することも可能です。Goスケジューラは、ゴルーチンがI/O待ちなどでブロックされる際に、そのゴルーチンを一時停止させ、他の実行可能なゴルーチンにCPUを割り当てることで、OSスレッドを最大限に活用します。

2. ネットワークI/Oとブロッキング/ノンブロッキング

一般的なネットワークI/O操作(例: readwriteaccept)は、データが利用可能になるか、または送信が完了するまでプログラムの実行を停止させる「ブロッキング」操作です。多数の接続を扱うサーバーアプリケーションでは、ブロッキングI/Oはスケーラビリティの問題を引き起こします。

これを解決するために、「ノンブロッキングI/O」と「I/O多重化」が用いられます。ノンブロッキングI/Oでは、I/O操作がすぐに完了しない場合でも、関数はすぐに制御を呼び出し元に戻し、操作が完了したかどうかを示すステータスを返します。

3. I/O多重化メカニズム

I/O多重化は、単一のスレッドで複数のI/O操作の準備状況を監視するためのメカニズムです。主要なOSが提供するI/O多重化メカニズムには以下のようなものがあります。

  • select/poll: 多くのUNIX系システムで利用可能な古いAPIですが、監視できるファイルディスクリプタの数に制限があったり、効率が悪い場合があります。
  • epoll (Linux): Linuxカーネルが提供する高性能なI/O多重化API。大規模な接続数でも効率的に動作します。
  • kqueue/kevent (BSD系OS, macOS): FreeBSD、NetBSD、OpenBSD、macOSなどのBSD系OSで利用されるイベント通知インターフェース。ファイルディスクリプタだけでなく、タイマーやプロセスイベントなど、様々なイベントを監視できます。
  • I/O完了ポート (IOCP) (Windows): Windowsが提供する高性能な非同期I/Oメカニズム。

4. Goのネットワークポーラー

Goランタイムは、これらのOSネイティブのI/O多重化メカニズムを抽象化し、「ネットワークポーラー」として利用します。Goのネットワークポーラーは、ゴルーチンがネットワークI/O操作を開始すると、そのゴルーチンをブロック状態にし、対応するファイルディスクリプタをOSのI/O多重化メカニズムに登録します。I/Oが完了してイベントが発生すると、ポーラーはそのイベントを検出し、対応するゴルーチンを「実行可能」状態に戻し、Goスケジューラがそのゴルーチンを再開します。これにより、GoプログラムはブロッキングI/Oを記述しながらも、内部的にはノンブロッキングかつ効率的なI/O処理を実現しています。

5. ビルドタグ(Build Tags)

Go言語では、ソースコードファイルの先頭に// +build tag1,tag2のようなコメントを記述することで、特定の環境(OS、アーキテクチャなど)でのみそのファイルをコンパイルするように制御できます。これを「ビルドタグ」と呼びます。コンパイラは、指定されたタグが現在のビルド環境と一致する場合にのみ、そのファイルをコンパイル対象に含めます。これにより、OSやアーキテクチャに依存するコードを適切に分離し、クロスプラットフォーム対応を容易にしています。

技術的詳細

このコミットの技術的な核心は、Goのビルドシステムにおけるビルドタグの変更を通じて、NetBSDをGoランタイムのネットワークポーラーの対象に含めることです。

Goのネットワークポーラーは、OSごとに異なる実装を持っています。BSD系のOSでは、kqueue/keventシステムコールがI/O多重化の基盤として利用されます。Goのnetパッケージ内には、これらのOS固有のポーラー実装を切り替えるためのビルドタグが設定されています。

変更前は、src/pkg/net/fd_bsd.gosrc/pkg/net/fd_poll_unix.goがNetBSDを含む特定のBSD系OS向けにコンパイルされていました。これらのファイルは、kqueue/keventを利用したFD(ファイルディスクリプタ)の待機ロジックを含んでいますが、fd_bsd.goは主にfreebsd,armnetbsd向け、fd_poll_unix.goも同様にfreebsd,armnetbsd向けに設定されていました。

一方で、src/pkg/net/fd_poll_runtime.goは、Goランタイムに統合された高性能なネットワークポーラーの実装を含んでいます。このファイルは、darwin(macOS)、freebsd,amd64freebsd,386linuxopenbsdwindowsといった主要なOS/アーキテクチャの組み合わせ向けにビルドされるように設定されていました。

このコミットでは、NetBSDをfd_poll_runtime.goのビルド対象に追加することで、NetBSD上でもGoのランタイム統合型ネットワークポーラーが利用されるようにします。これにより、NetBSDのGoプログラムは、kqueue/keventを介してGoランタイムのI/Oスケジューラと直接連携し、より効率的なノンブロッキングネットワークI/Oを実現できるようになります。

具体的には、以下の変更が行われています。

  1. src/pkg/net/fd_bsd.goからnetbsdビルドタグを削除。
  2. src/pkg/net/fd_poll_unix.goからnetbsdビルドタグを削除。
  3. src/pkg/net/fd_poll_runtime.gonetbsdビルドタグを追加。

この変更により、NetBSD環境でGoをビルドする際、fd_bsd.gofd_poll_unix.goの汎用的な(あるいは特定のアーキテクチャ向けの)ポーリングロジックではなく、fd_poll_runtime.goに含まれるGoランタイムに最適化されたポーリングロジックが選択されるようになります。これは、NetBSDが他の主要なOSと同様に、Goの高性能なネットワークI/Oスタックの恩恵を受けられるようになることを意味します。

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

このコミットでは、Goのネットワークパッケージ内の3つのファイルでビルドタグが変更されています。

1. src/pkg/net/fd_bsd.go

--- a/src/pkg/net/fd_bsd.go
+++ b/src/pkg/net/fd_bsd.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build freebsd,arm netbsd
+// +build freebsd,arm
 
 // Waiting for FDs via kqueue/kevent.
 
  • -// +build freebsd,arm netbsd
  • +// +build freebsd,arm netbsdタグが削除されました。これにより、このファイルはNetBSD向けにはコンパイルされなくなります。

2. src/pkg/net/fd_poll_runtime.go

--- a/src/pkg/net/fd_poll_runtime.go
+++ b/src/pkg/net/fd_poll_runtime.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin freebsd,amd64 freebsd,386 linux openbsd windows
+// +build darwin freebsd,amd64 freebsd,386 linux netbsd openbsd windows
 
 package net
 
  • -// +build darwin freebsd,amd64 freebsd,386 linux openbsd windows
  • +// +build darwin freebsd,amd64 freebsd,386 linux netbsd openbsd windows netbsdタグが追加されました。これにより、このファイルはNetBSD向けにもコンパイルされるようになります。

3. src/pkg/net/fd_poll_unix.go

--- a/src/pkg/net/fd_poll_unix.go
+++ b/src/pkg/net/fd_poll_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build freebsd,arm netbsd
+// +build freebsd,arm
 
 package net
 
  • -// +build freebsd,arm netbsd
  • +// +build freebsd,arm netbsdタグが削除されました。これにより、このファイルはNetBSD向けにはコンパイルされなくなります。

コアとなるコードの解説

このコミットのコード変更は、Goのビルドシステムにおけるビルドタグの調整のみであり、実際のGo言語のロジックやアルゴリズムの変更は含まれていません。しかし、このビルドタグの変更がGoプログラムの動作に与える影響は非常に大きいです。

  • fd_bsd.gofd_poll_unix.go からの netbsd タグ削除: これらのファイルは、おそらくNetBSDを含む一部のBSD系OSの特定のアーキテクチャ(例: freebsd,arm)向けに、kqueue/keventを利用したファイルディスクリプタのポーリングロジックを提供していたと考えられます。netbsdタグが削除されたことで、NetBSD環境ではこれらのファイルがコンパイル対象から外れます。これは、NetBSDがこれらのファイルで提供されるポーリングメカニズムではなく、より汎用的な、あるいはより最適化された別のメカニズムを使用するように切り替わることを意味します。

  • fd_poll_runtime.go への netbsd タグ追加: このファイルは、Goランタイムに深く統合された、高性能なネットワークポーラーの実装を含んでいます。このポーラーは、OSネイティブの効率的なI/O多重化メカニズム(Linuxのepoll、BSD系のkqueueなど)を抽象化し、GoのゴルーチンとI/Oスケジューラと密接に連携して動作します。netbsdタグが追加されたことで、NetBSD環境でGoをビルドする際に、このfd_poll_runtime.goがコンパイル対象に含まれるようになります。

結果として、NetBSD上でGoプログラムが実行される際、ネットワークI/OはGoランタイムの高性能なポーラーによって処理されるようになります。これにより、NetBSD上でのGoアプリケーションのネットワークパフォーマンスが向上し、多数の同時接続をより効率的に処理できるようになります。これは、Goが提供する並行処理のメリットをNetBSD環境でも最大限に引き出すための重要な変更と言えます。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード(src/pkg/netディレクトリ)
  • Go言語の公式ドキュメント
  • BSD系OSのkqueue/keventに関する一般的な情報
  • Goのネットワークポーラーに関する技術記事や議論(例: GoのIssueトラッカーやメーリングリスト)
  • Goのランタイムスケジューラに関する解説記事