channelのselectパターン、for break【Go】
selectパターン
複数channelを同時並行に処理したい場合に利用します。
selectを用いることで、複数channelの状態を、ブロックすることなしに同時に監視できます。
値がchannelに入ったものから順に処理されます。
defaultが記載されていない場合で、かつどのchannelにも値が入っていない場合には、
selectスコープ自体をブロッキングするため、forループであろうと無駄なCPUリソースの消費がありません。
defaultが記載されている場合には、上記ブロッキングは発生しません。
func goroutine1(c chan int) { for { c <- 1 time.Sleep(1 * time.Second) } } func goroutine2(c chan int) { for { c <- 2 time.Sleep(2 * time.Second) } } func main() { c1 := make(chan int) c2 := make(chan int) go goroutine1(c1) go goroutine2(c2) t := time.NewTimer(5 * time.Second) // 便宜上、タイマーを用意 defer t.Stop() for { select { case <-t.C: // タイマーの指定時間を超えたら終了させる close(c1) close(c2) return // main関数による処理を終了する case msg1 := <-c1: // <-を用いた、値の代入または破棄が必要 fmt.Println(msg1) case msg2 := <-c2: // <-を用いた、値の代入または破棄が必要 fmt.Println(msg2) } } }
for break
先述の例ですと、タイマーの指定時間を超えたらmain関数内の処理が終了してしまいますが、
forループに名前をつけて、breakするようにすれば、forループだけを抜けることができます。
func goroutine1(c chan int) { for { c <- 1 time.Sleep(1 * time.Second) } } func goroutine2(c chan int) { for { c <- 2 time.Sleep(2 * time.Second) } } func main() { c1 := make(chan int) c2 := make(chan int) go goroutine1(c1) go goroutine2(c2) t := time.NewTimer(5 * time.Second) defer t.Stop() selectLoop: // 任意の名前を付ける for { select { case <-t.C: close(c1) close(c2) break selectLoop // 名前をつけたこのループをbreak case msg1 := <-c1: fmt.Println(msg1) case msg2 := <-c2: fmt.Println(msg2) } } fmt.Println("***********") // selectLoopを抜けたら到達する }
ゴルーチン、チャネルを利用した並行パターン / fujimisakari blog
www.slideshare.net