問題
Go言語をちゃんと学ぼうと思っていろいろ勉強してるのだけれど
- ダックタイピングって一体なんなのよ【golang】 - DRYな備忘録
- Go言語に継承は無いんですか【golang】 - DRYな備忘録
- Go言語のgoroutineって一体何よ【golang】 - DRYな備忘録
いよいよgoroutineの実践。
並行処理を書くうえで大きな課題のひとつはデータの共有らしいが、Go言語はこれをchannel
というtypeで実装することを推奨している。
チャネル( Channel )は、チャネルオペレータの <- を用いて値の送受信ができる直通ルートの型です。 A Tour of Go
( ゚д゚)... は?
しらべてみよう
やっぱり
が分かりやすい
並行処理プログラミングには、ざっくり分けて二つのアプローチがあります。
Shared-memory communication
ワーカ間でメモリ(リソース) を共有する。レースコンディションが起こらないようにロックをとることが多く、その実装は難しいことが多いとされる。 Message-passing communication
ワーカ間でメッセージパッシングを行う。Erlang などに実装された Actor モデルなどが代表的な実装。
ふむふむ
そして、Go の並行処理モデルの方針は下記に宣言されています。
"Do not communicate by sharing memory; instead, share memory by communicating"
ほう
Channel とは
- Channel は goroutine 間でのメッセージパッシングをするためのもの
- メッセージの型を指定できる
- first class value であり、引数や戻り値にも使える
- send/receive でブロックする
- buffer で、一度に扱えるメッセージ量を指定できる
なるほどだいぶ理解
やってみよう
package main import ( "fmt" ) func listenChannel(myCh chan int) { // myChからの送信を受け取る for out := range myCh { fmt.Println( fmt.Sprintf("out from channel => %d",out), ) } } func main() { fmt.Println("This is func main") // intを送受信どちらもできるchannel myChan := make(chan int) // 並行処理goroutineを立ち上げる go listenChannel(myChan) myChan <- 100 // 100を流し込む fmt.Printf("main exited now") }
その結果
[9:46:17] → go run sample.go This is func main out from channel => 100 main exited now
おおよそ期待通り。
まあできるよねー、ってんでこうしてみた。
diff -u sample.origin.go sample.go
--- sample.origin.go 2014-01-22 09:48:58.000000000 +0900 +++ sample.go 2014-01-22 09:49:21.000000000 +0900 @@ -20,6 +20,7 @@ go listenChannel(myChan) myChan <- 100 // 100を流し込む + myChan <- 200 // さらに200を流し込む fmt.Printf("main exited now") }
その結果
[9:49:23] → go run sample.go This is func main out from channel => 100 main exited now
( ゚д゚) ...ン? 200の流し込みを受け取れてない?
goroutineのはなし
そういえば、
main内で定義したgoroutineは、mainが死ねば死ぬ
ということは
こうではないか
--- sample.origin.go 2014-01-22 09:48:58.000000000 +0900 +++ sample.go 2014-01-22 09:56:20.000000000 +0900 @@ -2,6 +2,7 @@ import ( "fmt" + "time" ) func listenChannel(myCh chan int) { for out := range myCh { @@ -20,6 +21,8 @@ go listenChannel(myChan) myChan <- 100 // 100を流し込む + myChan <- 200 // さらに200を流し込む + time.Sleep(1 * time.Second)// mainを延命する fmt.Printf("main exited now") }
どうだ
[9:56:22] → go run sample.go This is func main out from channel => 100 out from channel => 200 main exited now
おk
送信、受信のしばりとかは、読んだり書いたりしながら随時追記するかも
DRYな備忘録