モジュール 7 · レッスン 1 / 5コース内の 31/50~12 min
モジュールのレッスン (1/5)
ゴルーチン: 軽量の並列処理
ゴルーチン は、Go によって管理される同時実行の単位です。
ランタイム。関数の前に go キーワードを付けて起動します。
電話:
Go
go greet("Anna") // chiamata a funzione esistente
go func() { // funzione anonima
fmt.Println("hi")
}()go ステートメントは 即時 を返します。ゴルーチンは で開始されます。
並行して、呼び出し側は続行します。
なぜ「軽い」のか
- 初期スタック ~2KB (必要に応じて最大数百 MB まで動的に増加します)。
- ランタイムによって少数の OS スレッドに 多重化されます (
GOMAXPROCS)。 - 数千/数百万のゴルーチンは日常的なものです。 OS スレッドではそれは不可能です。
概念的には、これは「同時ファイアアンドフォーゲット」ですが、
調整するための慣用的なツール (チャネル、sync.WaitGroup、
context)。
メインは待ちません
Go
func main() {
go func() { fmt.Println("ciao dalla goroutine") }()
// main esce subito: niente garanzia che la goroutine completi
}main が返されると、プロセスは終了します。ゴルーチンは取得されません。
「仕事を終える」ために、彼らはただ一緒に殺されるだけです。
プロセス。明示的な同期が必要です。
同期: プレビュー
次のレッスンで説明する 3 つのツール:
Go
// 1) Channel: la goroutine "segnala" via canale
done := make(chan struct{})
go func() {
work()
done <- struct{}{}
}()
<-done // attendi
// 2) sync.WaitGroup: N goroutine
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); work() }()
wg.Wait()
// 3) context: cancellazione/timeout propagati「古典的な」ループ内クロージャのバグ
Go 1.21 まで、これはよくある問題でした。
Go
for i := 0; i < 3; i++ {
go func() { fmt.Println(i) }() // stampa "3 3 3" su versioni vecchie
}Go 1.22 から、for 変数がそれぞれの環境で新たに作成されます。
反復するため、バグはデフォルトで修正されます。古いコードベースでは、
まだ修正パターンが表示されます。
Go
for i := 0; i < 3; i++ {
i := i // shadow esplicito
go func() { fmt.Println(i) }()
}
// oppure passa come argomento:
for i := 0; i < 3; i++ {
go func(n int) { fmt.Println(n) }(i)
}Goroutine != OS スレッド
| 側面 | ゴルーチン | OSスレッド |
|---|---|---|
| 初期スタック | ~2KB | 1 ~ 8 MB (開始時に割り当てられます) |
| 創造 | ナノ秒 | マイクロ秒 |
| スケジューリング | Go ランタイム (連携) | カーネル (プリエンプティブ) |
| 実用的なカウント | 10万以上 | 数千 |
単一の OS スレッドで多数のゴルーチンをホストできます。ランタイムが動く 必要に応じてスレッド間でゴルーチンを実行します。
試してみてください
運動#go.m7.l1.e1
試行回数: 0読み込み中…
ゴルーチンとして挨拶関数を起動し、メインを終了する前に時間とともに 100 ミリ秒待機します。スリープします。
エディターを読み込み中…
ヒントを表示
関数呼び出しの前に「go」を付けると、ゴルーチンが起動されます。
3 回の試行後に解決策が利用可能になります
運動#go.m7.l1.e2
試行回数: 0読み込み中…
「hi」を出力するゴルーチンとして匿名関数を起動します。
エディターを読み込み中…
ヒントを表示
匿名関数は、末尾に `()` を付けて呼び出されます: `go func(){...}()`。
3 回の試行後に解決策が利用可能になります
Quiz#go.m7.l1.e3
準備完了goroutine が完了する前に「main」が終了するとどうなりますか?
Go
func main() {
go work()
// main ritorna immediatamente
}要約
go f()は f() を同時に起動します。すぐに戻ってきます。- Goroutine = 初期サイズは約 2 KB、いくつかの OS スレッドに多重化されます。
mainは待機しません。同期 (チャネル/待機グループ/コンテキスト) が必要です。time.Sleepは単なる教訓であり、運用環境での同期には決して使用されません。- Go 1.22 以降、
for変数は反復ごとに「最新」になります (「3 3 3」バグはなくなりました)。