Go netpoller

Goランタイムが持つ、I/Oの多重化(epoll/kqueue/IOCPなど)をgoroutineスケジューラと統合する内部レイヤー。GoのosReadがO_NONBLOCK+EAGAINでもブロックする問題の直接の原因になっている仕組み。

設計思想

Goの標準ライブラリは、ソケットやファイルへのRead/Writeをアプリケーションコードから見て素朴な「ブロッキング呼び出し」のように書かせる。コールバックベースの非同期I/O(イベントループにハンドラを登録するスタイル)は制御フローを追いにくくするため、Goはその複雑さをランタイム内部に押し込め、開発者にはepoll_create/epoll_ctl/epoll_waitを一切触らせない設計を選んでいる。

主要な関数(Linux実装: runtime/netpoll_epoll.go)

  • netpollinit() — epollインスタンスの作成。プログラム全体で1回だけ呼ばれる。
  • netpollopen(fd, pd) — 対象のファイルディスクリプタをエッジトリガーでepoll_ctlに登録する。
  • netpoll(delta)epoll_waitを実行する本体。deltaが負なら無限待機、0ならノンブロック、正ならその時間だけ待機。
  • netpollBreak()netpollがブロック中のときに強制的に起こすための唤起機構。

pollDesc とgoroutineの休止・再開

各fdにはpollDescという構造体が対応付けられ、その fd を読み待ち/書き待ちしているgoroutineへのポインタ(rg/wg)を保持する。

  • 休止時: read(2)などがEAGAINを返すと、ランタイムはnetpollblockを呼び、goparkで該当goroutineをスケジューラから外して休眠させる。この時点でOSスレッド(M)は解放され、他のgoroutineの実行に回せる。
  • 再開時: netpollepoll_waitでfdのready状態を検出すると、対応するpollDescから休止中のgoroutineをgoreadyで実行可能状態に戻す。

スケジューラ(GMPモデル)との統合

goroutineスケジューラのfindRunnableは、実行可能なgoroutineを探す過程でruntime.netpollを呼び出す。さらに、バックグラウンドで動くsysmonスレッドも約10ms間隔でnetpollを実行し、非同期的にI/Oイベントを拾い上げる。この統合により、「netpollが1個で済んでいるランタイム全体の窓口」として機能し、複数スレッドが同時にepollへブロックしないよう排他制御されている。

出典

#golang #linux

作成日時: 2026-08-15 09:14 / 更新日時: 2026-08-15 09:14