スキップしてメイン コンテンツに移動

Go初心者の並行処理入門

Go初心者の並行処理入門

Go初心者のための並行処理入門

Goは軽量スレッドであるゴルーチンを使って、並行処理を簡単に実装できます。並行処理は複数のタスクを同時に実行することで、CPUやI/Oの待ち時間を短縮し、アプリケーションの応答性を向上させます。Go初心者が最初に覚えておくべきポイントは、goroutineは関数呼び出しのように簡単に起動でき、内部でスレッドプールが管理してくれることです。

以下は、簡単な並行処理の例です。2つのgoroutineを起動し、チャネルで結果を受け取ります。

package main

import (
    "fmt"
    "time"
)

func worker(id int, ch chan int) {
    time.Sleep(time.Duration(id) * time.Second)
    ch <- id
}

func main() {
    ch := make(chan int, 2)
    go worker(1, ch)
    go worker(2, ch)

    for i := 0; i < 2; i++ {
        fmt.Println("Result:", <-ch)
    }
}

ゴルーチンとgoroutineの基本

ゴルーチンはGoの軽量スレッドで、goroutineというキーワードで起動します。goroutineはスタックが自動で伸縮し、数十万個まで起動可能です。goroutineを起動するには go キーワードを関数呼び出しの前に付けるだけです。

goroutineは非同期に実行されるため、呼び出し元のコードはすぐに次の行へ進みます。非同期処理と並列実行は似ているようで、実際には並列実行は複数のCPUコアで同時に動くことを意味します。Goはデフォルトでマルチコアを活用し、goroutineを複数のスレッドに分散します。

goroutineの同期にはチャネルやWaitGroupが便利です。チャネルはデータの送受信を安全に行うための通信手段で、WaitGroupは複数のgoroutineが完了するまで待機するために使います。

非同期と並列実行の違い

非同期は「タスクを開始してすぐに次の処理へ進む」ことを指し、並列実行は「複数のタスクを同時に実行する」ことです。Goではgoroutineを使うことで非同期と並列実行の両方を簡単に実装できます。

例えば、HTTPリクエストを複数同時に送る場合、goroutineを使って非同期にリクエストを発行し、チャネルで結果を集約します。これにより、I/O待ち時間を短縮し、全体のレスポンスタイムを改善できます。

以下は非同期HTTPリクエストの例です。

package main

import (
    "fmt"
    "net/http"
    "sync"
)

func fetch(url string, wg *sync.WaitGroup, ch chan string) {
    defer wg.Done()
    resp, err := http.Get(url)
    if err != nil {
        ch <- fmt.Sprintf("Error: %v", err)
        return
    }
    ch <- fmt.Sprintf("Fetched %s: %d", url, resp.StatusCode)
}

func main() {
    urls := []string{
        "https://example.com",
        "https://golang.org",
    }
    var wg sync.WaitGroup
    ch := make(chan string, len(urls))

    for _, url := range urls {
        wg.Add(1)
        go fetch(url, &wg, ch)
    }

    wg.Wait()
    close(ch)

    for msg := range ch {
        fmt.Println(msg)
    }
}

コンカレンシー設計のベストプラクティス

Goで安全かつ効率的にコンカレンシーを設計するためのポイントをまとめます。

  • チャネルは型安全で、データの送受信を明示的に管理できるため、競合状態を防止します。
  • WaitGroupを使ってgoroutineの終了を待機し、リソースリークを防ぎます。
  • select文で複数チャネルを同時に待機し、タイムアウトやキャンセルを実装します。
  • goroutineの数は必要に応じて制限し、過剰なスレッド生成を避けます。必要ならruntime.GOMAXPROCSでCPU数を設定します。
  • エラーハンドリングは必ず行い、失敗したgoroutineを適切にクリーンアップします。

これらのベストプラクティスを守ることで、Go初心者でも安全に並行処理を実装でき、軽量スレッドを活用した非同期・並列実行が可能になります。

この記事はAIによって作成されました。

コメント