DRYな備忘録

Don't Repeat Yourself.

Go言語のchannelって一体何よ ~基礎編~【golang】

問題

Go言語をちゃんと学ぼうと思っていろいろ勉強してるのだけれど

いよいよ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な備忘録