Go/go
表示
< Go
Goにおけるgoキーワードは、ゴルーチン(goroutine)を起動するために使用される重要な機能です。ゴルーチンはGoの並行処理の中核であり、軽量スレッドとして動作します。
基本的な使い方
[編集]go 関数呼び出し
この構文で新しいゴルーチンが作成され、指定された関数が並行して実行されます。
主な特徴
[編集]- 軽量: ゴルーチンはOSスレッドよりも遥かに軽量で、数千〜数百万のゴルーチンを同時に実行可能
- スケジューリング: GoランタイムによるM:Nスケジューリングでリソースを効率的に使用
- 通信: チャネル(channel)を使用してゴルーチン間でデータを安全に共有
他のキーワードとの組み合わせとユースケース
[編集]1. 無名関数との組み合わせ
[編集]go func() { // 実行したい処理 }()
ユースケース:
- バックグラウンド処理
- 一時的なタスク実行
- クロージャとしてローカル変数へのアクセス
ch := make(chan int) go func() { result := someCalculation() ch <- result // 結果をチャネルに送信 }() value := <-ch // チャネルから結果を受信
ユースケース:
- 非同期処理の結果取得
- ゴルーチン間の通信と同期
- イベントベースの処理
go func() { for { select { case data := <-dataChan: processData(data) case <-quitChan: cleanup() return case <-time.After(timeout): handleTimeout() } } }()
ユースケース:
- 複数チャネルの監視
- タイムアウト処理
- 終了シグナル処理
4. WaitGroupとの組み合わせ
[編集]var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func(id int) { defer wg.Done() processItem(id) }(i) } wg.Wait() // すべてのゴルーチンが完了するまで待機
ユースケース:
- 複数ゴルーチンの完了同期
- バッチ処理
- 並列データ処理
5. Mutexとの組み合わせ
[編集]var mu sync.Mutex counter := 0 for i := 0; i < 1000; i++ { go func() { mu.Lock() counter++ mu.Unlock() }() }
ユースケース:
- 共有リソースへの安全なアクセス
- データ競合の防止
- クリティカルセクションの保護
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() go func(ctx context.Context) { select { case <-ctx.Done(): log.Println("処理がキャンセルされました:", ctx.Err()) return case <-time.After(10 * time.Second): log.Println("処理が完了しました") } }(ctx)
ユースケース:
- キャンセル可能な処理
- タイムアウト制御
- リソースのクリーンアップ
7. エラー処理との組み合わせ
[編集]errCh := make(chan error, 1) go func() { if err := riskyOperation(); err != nil { errCh <- err } close(errCh) }() if err := <-errCh; err != nil { log.Fatalf("エラーが発生しました: %v", err) }
ユースケース:
- 非同期エラーハンドリング
- エラー伝播
- 障害検出
8. HTTPサーバーとの組み合わせ
[編集]http.HandleFunc("/", handler) go func() { log.Fatal(http.ListenAndServe(":8080", nil)) }() // メインプログラムはその他の処理を続行
ユースケース:
- バックグラウンドでのサーバー起動
- マイクロサービス
- 複数のサービス同時起動
9. ワーカープールパターン
[編集]func workerPool(numWorkers int, jobs <-chan Job, results chan<- Result) { for i := 0; i < numWorkers; i++ { go worker(i, jobs, results) } } func worker(id int, jobs <-chan Job, results chan<- Result) { for job := range jobs { results <- processJob(job) } }
ユースケース:
- 負荷分散
- スケーラブルな処理
- リソース使用の最適化
10. パイプラインパターン
[編集]func pipeline() { in := gen(1, 2, 3, 4) out := sq(in) for result := range out { fmt.Println(result) } } func gen(nums ...int) <-chan int { out := make(chan int) go func() { for _, n := range nums { out <- n } close(out) }() return out } func sq(in <-chan int) <-chan int { out := make(chan int) go func() { for n := range in { out <- n * n } close(out) }() return out }
ユースケース:
- データ処理パイプライン
- ストリーミング処理
- 変換チェーン
使用上の注意点
[編集]- 変数キャプチャ: ループ内で変数をキャプチャする際は要注意
- 終了処理: メインプログラムが終了するとゴルーチンも強制終了される
- リソース管理: 大量のゴルーチンを起動する場合はリソース使用に注意
- データ競合: 共有変数へのアクセスは適切に同期する必要がある
- エラー処理: ゴルーチン内のパニックはメインプログラムに伝播しない
goキーワードはGoの並行プログラミングモデルの中心的な機能であり、適切に使用することで効率的で信頼性の高い並行処理を実現できます。