ゴルーチンの起動
goキーワード、ゴルーチンのライフサイクル、WaitGroup
「ゴルーチンの起動」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
ゴルーチンとは
ゴルーチンは、Goランタイムによって管理される軽量な並行実行関数です。ゴルーチンはOSスレッドよりもはるかに低コストなので、数千個を実行できます:
goキーワードで開始します- 初期スタックは約2KBです(動的に拡張されます)
- OSではなくGoランタイムによってスケジュールされます
- 共有メモリではなく、チャネルを介して通信します
goキーワード
関数呼び出しの前に goを付けると、ゴルーチンとして起動できます:
package main
import ("fmt"; "time")
func greet(name string) {
fmt.Printf("Hello, %s!\n", name)
}
func main() {
go greet("Alice") // runs concurrently
go greet("Bob") // runs concurrently
time.Sleep(100 * time.Millisecond) // wait for goroutines
fmt.Println("done")
}ゴルーチンのライフサイクル
ゴルーチンは goステートメントが実行されたときに開始し、その関数が戻ると終了します。mainが戻ると、すべてのゴルーチンが終了します:
package main
import ("fmt"; "time")
func worker(id int) {
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Duration(id) * 50 * time.Millisecond)
fmt.Printf("Worker %d done\n", id)
}
func main() {
for i := 1; i <= 3; i++ {
go worker(i)
}
time.Sleep(300 * time.Millisecond) // naive wait
}同期に使うsync.WaitGroup
ゴルーチンの完了を待つには、スリープではなく sync.WaitGroupを使用します:
package main
import ("fmt"; "sync")
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // signal completion
fmt.Printf("Worker %d working\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1) // register one goroutine
go worker(i, &wg)
}
wg.Wait() // block until all Done()
fmt.Println("all workers finished")
}匿名ゴルーチン
匿名関数をゴルーチンとして直接起動します。インラインの並行タスクに便利です:
package main
import ("fmt"; "sync")
func main() {
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
i := i // capture loop variable
wg.Add(1)
go func() {
defer wg.Done()
fmt.Printf("goroutine %d\n", i)
}()
}
wg.Wait()
}ループ変数のキャプチャに関する注意点
ループ変数をキャプチャしないと、すべてのゴルーチンが同じ(最後の)値を参照する可能性があります。これはGoでよくある並行処理のバグです:
package main
import ("fmt"; "sync")
func main() {
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func(n int) { // pass i as argument — safe
defer wg.Done()
fmt.Println(n) // prints 0, 1, 2 in some order
}(i)
}
wg.Wait()
}ゴルーチンとスレッドの比較
OSスレッドよりもゴルーチンが推奨される理由:
- 初期スタックは2KBで、OSスレッドの約1MBより小さい
- 作成にかかる時間はミリ秒ではなくマイクロ秒です
- Goランタイムは、GOMAXPROCS個のOSスレッド上でゴルーチンを多重化します
- ゴルーチンの切り替えは協調的に行われ、カーネルは関与しません
- スケジューリングはGoが処理するため、ロジックに集中できます
GOMAXPROCS
runtime.GOMAXPROCSは、ゴルーチンを並列に実行するOSスレッドの数を制御します(デフォルトはCPU数です):
package main
import ("fmt"; "runtime")
func main() {
// Default: number of available CPU cores
fmt.Println("CPUs:", runtime.NumCPU())
fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0)) // 0 = query without changing
// Set to 1 for debugging race conditions:
// runtime.GOMAXPROCS(1)
fmt.Println("Goroutines:", runtime.NumGoroutine())
}ゴルーチンリーク
ゴルーチンリークは、ゴルーチンが起動されたものの、決して終了しない場合に発生します。よくある原因は、チャネルの受信待ち、ミューテックスのロック待ち、キャンセル処理がないことです:
package main
import ("fmt"; "time"; "runtime")
func leaky() {
ch := make(chan int) // nobody sends to ch
go func() {
v := <-ch // blocks forever — goroutine leaked!
fmt.Println(v)
}()
}
func main() {
leaky()
time.Sleep(10 * time.Millisecond)
fmt.Println("goroutines:", runtime.NumGoroutine()) // > 1
}ゴルーチンのベストプラクティス
ゴルーチンに関するガイドライン:
- ゴルーチンがどのように終了するかを必ず把握します
- 同期にはスリープではなく、WaitGroupまたはチャネルを使用します
- ループ変数はクロージャ経由ではなく、関数の引数として渡します
- コンテキストでゴルーチンをキャンセルし、実行したまま放置しないようにします
- 競合検出器を使用します:
go run -race main.go
確認問題
ゴルーチンでループ変数のキャプチャバグを回避する正しい方法は何ですか?
復習: ゴルーチンの起動
まとめ:
go fn()で起動します — 軽量で低コストです- 待機には
sync.WaitGroupを使用します:Add(1)、defer Done()、Wait() - ループ変数は引数または再宣言によってキャプチャします
- 各ゴルーチンがどのように終了するかを必ず把握し、リークを防ぎます
- データ競合の検出には
-raceフラグを使用します
よくある質問
「ゴルーチンの起動」レッスンは無料ですか?
はい。「ゴルーチンの起動」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「ゴルーチンの起動」で何を学びますか?
goキーワード、ゴルーチンのライフサイクル、WaitGroup ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「ゴルーチンの起動」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。