golangのgoroutineスケジューリングの実装原理について教えてください

Go言語のゴルーチン スケジューラは、M:Nスケジューリングと呼ばれる手法を使っています。これは、M個のユーザーレベルスレッド(ゴルーチンとも呼ばれます)が、N個のカーネルレベルスレッド(OSスレッドとも呼ばれます)で実行されるようにスケジュールされることを意味します。

スケジューラの実装の仕組みは、以下の通りです。

  1. 起動時に、スケジューラはMと呼ばれる一組のOSスレッドを作成します。これらのスレッドはgoroutineの実行を担当します。
  2. スケジューラはgoroutineを実行する必要があるとき、それをグローバルキューに入れる。
  3. アイドル状態の M があれば、スケジューラはそれを選択してキューイングされているゴルーチンを実行します。アイドル状態の M がなければ、スケジューラは新しい M を作成します。
  4. このゴルーチンは、time.Sleep()やruntime.Gosched()などの関数を呼び出して、実行権を自発的に放棄します。
  5. このgoroutineは待機状態、例えばI/O操作が完了するのを待つか、チャンネルによるデータを待っている状態です。
  6. 関数が終了した、即ち goroutine が完了した。
  7. 長時間にわたって処理を実行しているゴルーチンが一定のしきい値を超過すると、スケジューラーがそれをプリエンプトして再スケジュールします。
  8. ゴルーチンがブロックされると、M は現在のスレッドからデタッチされ、スレッドは他のゴルーチンに使用可能なアイドル状態になる。
  9. ブロックされたgoroutineが実行可能な状態になると、スケジューラはそれをグローバルキューに再配置し、実行する空きMを選択します。
  10. あるMが一定数のgoroutineを実行し終えると、グローバルキューにまだ実行されていないgoroutineが残っているかどうかをチェックする。ある場合はそれらを実行し続ける。そうでない場合は、Mは休止状態に入り、新しいgoroutineが来るのを待つ。
  11. スリープ状態のMは、すべてのMに実行時間が確保されるように、スケジューラにより定期的にウェイクアップされます。

スケジューラーは、負荷分散や先取り実行などのポリシーに基づき、M と Goroutine の選択方法を決定します。この M:N スケジューリングパターンは、マルチコアプロセッサのリソースを最大限に活用し、効率的な並列実行を実現します。

bannerAds