GOルーチンおさらい
基本的なGOルーチン
sample.go
package main import ( "fmt" "time" ) func main() { fmt.Println(1) go routine() fmt.Println(3) } func routine() { time.Sleep(1 * time.Second) fmt.Println(2) }
実行結果
[vagrant@localhost 20160404]$ go run sample.go 1 3
main()が終了すると共に終了となる。 GOルーチンの処理を最後まで実行させる為、main側で処理が終わった事の通知を受け取るまで待機
package main import ( "fmt" "time" "log" ) func main() { // チャンネルの作成 ch := make(chan string) fmt.Println(1) go routine(ch) // チャンネルのメッセージを受信(ここで受信するまで待ちます) res, ok := <- ch log.Printf("res -> %v, ok -> %v", res, ok) // fmt.Println(3) } func routine(ch chan string) { time.Sleep(2 * time.Second) fmt.Println(2) // チャンネルにメッセージ"finish"を送信 ch <- "finish" }
実行結果
[vagrant@localhost 20160404]$ go run sample.go 1 2 2016/04/04 14:39:52 res -> finish, ok -> true 3
メッセージを受信するまでWaitし、順番に処理される事が確認できました。<-ch で受信結果を受け取ると、第一引数にメッセージ、第二引数に受信結果を受け取れます。
バッファリング
package main import "fmt" func main() { ch := make(chan int, 2) ch <- 1 ch <- 2 fmt.Println(<-ch) fmt.Println(<-ch) }
実行結果
1 2
バッファを超える数を指定するとFatal Error
package main import "fmt" func main() { ch := make(chan int, 2) ch <- 1 ch <- 2 ch <- 3 fmt.Println(<-ch) fmt.Println(<-ch) fmt.Println(<-ch) }
fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan send]: main.main() /home/vagrant/work/20160404/buff.go:9 +0xc4 exit status 2
Channelクローズ
v, ok := <-ch
で第二引数でチャンネルクローズしたかどうかを受け取れる
package main import ( "fmt" ) func routine(n int, c chan int) { x, y := 0, 1 for i := 0; i < n; i++ { c <- x x, y = y, x+y } close(c) } func main() { c := make(chan int, 10) go routine(cap(c), c) for i := range c { fmt.Println(i) } }
実行結果
0 1 1 2 3 5 8 13 21 34
Select
package main import "fmt" func routine(c, quit chan int) { x, y := 0, 1 for { select { case c <- x: x, y = y, x+y case <-quit: fmt.Println("quit") return } } } func main() { c := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { fmt.Println(<-c) } quit <- 0 }() routine(c, quit) }
実行結果
0 1 1 2 3 5 8 13 21 34 quit
GO TOURからの拝借コードとなりますが、自分自身の備忘という事で。今後は実用例などもアップしていこうと思います