goroutineの実行パターン

最近、Go言語による並行処理を読んでいる。その中で明示的には紹介されていないものの、頻繁に登場するコードを整理して理解したい。

以下のコード例では、goroutineを実行してその結果を受信するchannelを取得できる関数を定義している。

// goroutineの結果を表す型
type result struct {
  value int
  err   error
}

generate := func() <-chan result {
  // 送受信可能なchannelを生成する
  ch := make(chan result)

  // channelに結果を送信するgoroutineを実行する
  go func() {
    // channelを確実に終了させる
    defer close(ch)

    err := something()
    if err != nil {
      ch <- result{value: -1, err: err}
      return
    }

    ch <- result{value: 1, err: nil}
  }()

  // 返り値の型が<-chanなので受信専用のchannelとして返る
  return ch
}
  • 関数の返り値が<-chan resultになっているため、この関数を呼び出す側はこのchannelから値を受信することしかできない。
  • goroutine内でdeferによって確実にchannelを終了させる。
  • goroutineの結果を表す型を定義してerrorを含めた値をchannelに送ることで、呼び出す側でエラーハンドリングできるようにしている。