Goは、高性能なネットワークおよび並行プログラムを書くために設計されているため、組み込みのスケジューラーとゴルーチンを使用した簡単な並行性管理に特に重点が置かれています。ほとんどの言語ではOSスレッドがユーザーによって直接管理されますが、Goではゴルーチンが軽量で、何千ものゴルーチンが固定された数のシステムスレッドの上で同時に動作できます。
問題: スレッドの直接管理は難しい:これにより、リソースの迅速な消費、データレース、およびメモリ管理の複雑さが引き起こされます。
解決策: GoはM:Nモデルを使用しており、大量のゴルーチン(M)が限られた数のOSスレッド(N)上でマルチプレックスされます。これを実現しているのがGoランタイムレベルに実装されたスケジューラーであり、ゴルーチンの実行を自動的にバランスと再配分を行います。プログラマはOSスレッドを直接管理するのではなく、ゴルーチンの起動と同期のみを管理します。
コードの例:
package main import ( "fmt" "time" ) func worker(id int) { fmt.Printf("Worker %d starting ", id) time.Sleep(time.Second) fmt.Printf("Worker %d done ", id) } func main() { for i := 0; i < 5; i++ { go worker(i) } time.Sleep(2 * time.Second) }
主な特徴:
各ゴルーチンは別々のCPUコアで同時に実行されるのですか?
いいえ。ゴルーチンはマルチプレックスされ、スケジューラーが同時に実行されるタスクの実際の数を決定します。
特定のゴルーチン/スレッドの実行を手動で管理できますか?
いいえ。Goランタイムは直接スケジューリングするためのインターフェースを提供していません。例外は、OSスレッド数を設定するためのGOMAXPROCSです。
多くのゴルーチンがあるとプログラムが自動的に速くなりますか?
いいえ。多くの同時操作は、コンテキストスイッチ、リソース競合、GCの時間とメモリ使用量の増加といった追加のオーバーヘッドを引き起こす可能性があります。
マイクロサービスは、到着するリクエストを並行して処理し、ゴルーチンの数を制限せず、WaitGroupを使って完了を待たなかった — 結果として、応答時間の増加、データレース、不規則なタイムアウトが発生しました。
長所:
短所:
ワーカーの管理者はゴルーチンプールを通じて実装されており、同時に動作するタスクの数はセマフォやチャネルで制限されています。WaitGroupはすべてのタスクが終了するまで正しく待機します。
長所:
短所: