😀

【go言語】doneチャネルの理解

2024/02/24に公開

初めてのGo言語 10.5.4 doneチャネルパターンについての理解メモ

※そのまま実行できます

package main

import (
	"fmt"
)

func searchData(s string, datas []string) string {
	done := make(chan struct{})
	resultChan := make(chan string)
	for _, data := range datas {
		go func(data string) {
			select {
			case resultChan <- data:
				fmt.Println("結果が戻ってきた")
			case <-done:
				return
			}
		}(data)
	}

	// 1番目の結果を受け取る
	r1 := <-resultChan
	r2 := <-resultChan
	r3 := <-resultChan
	r4 := <-resultChan
	fmt.Printf("r1:%v\n", r1)
	fmt.Printf("r2:%v\n", r2)
	fmt.Printf("r3:%v\n", r3)
	fmt.Printf("r4:%v\n", r4)
	close(done)       // 他のゴルーチンを中断する
	close(resultChan) // 他のゴルーチンを中断する
	r5 := <-resultChan
	fmt.Printf("r5:%v\n", r5)
	doneValue := <-done
	fmt.Printf("doneValue:%v\n", doneValue)
	return r1
}

func main() {
	r1 := searchData("e", []string{
		"apple",
		"banana",
		"cherry",
		"date",
		"elderberry",
		"fig",
		"grape",
	})
	fmt.Printf("1番目の結果: %v\n", r1)

}

結果

結果が戻ってきた
r1:grape
r2:cherry
r3:apple
r4:banana
r5:
doneValue:{}
1番目の結果: grape

学び

  • 並行処理の順番は順不同なので、r1,r2,r3,r4の結果が配列の順番通りではない
  • その中で一番最初に終わった処理grapeがmain関数の1番目の結果として返ってきてる
  • クローズされたチャネルは無限にゼロ値が返ってくる(何回読み取ってもゼロ値を読み取れる)
  • クローズ前のチャネルの値を2回以上読み取ろうとすると、その値に書き込まれてない場合デッドロック起こして読み込めない
    • バッファなしチャネルで、クローズ前は、何かが書き込まれるまでポーズして、永遠にポーズしているのでデッドロックが起こっている

おまけ

上記のdoneチャネルパターンを各所で利用したい場合、countToのような関数を定義して、各所で使えるようにしておくこともできる

func countTo(max int) (<-chan int, func()) {
    ch := make(chan int)
    done := make(chan struct{})
    cancelFunc := func() { // chをクローズする関数を戻す
        close(done)
    }

    go func() {
        for i := 0; i < max; i++ {
            select {
            case <-done:
                return
            case ch <- i:
            }
        }
        close(ch)
    }()
    return ch, cancelFunc
}

func main() {
     ch, cancelFunc := countTo(10)
    for i := range ch {
        if i >= 5 {  // 途中で抜けたくなったら(抜ける条件が整ったら)
“件が整ったら)
            break
        }
        fmt.Print(i, " ")
    }
    fmt.Println()
    cancelFunc() // chをクローズしてforループを終了する
}


Discussion