2012/09/20

Go言語の並列処理 (channel)

chennel とは

  • goroutine 間の通信を調整するランタイムオブジェクト
  • channel はどんな値でも通信できる。
  • マップと同じくチャネルは参照型。
  • make()を使って作成する。
  • channel にはバッファなしとバッファありがある。

バッファなし channel

同期チャネル。

  • 送信データは受信側が直接受け取るしかない
  • 受信側が他のことをしていて、受信状態になければ、送信側は待たされる
  • 受信側が受信状態なら、送信する
  • 送信側が送信しているときは、受信者は受信している。= 同期している

CSPモデルの動作原理

バッファあり channel

非同期チャネル。

  • バッファを Queue として扱う。
  • 受信側は送信されたデータがなければ待つ。
  • 送信側はバッファに空きがあれば、値がバッファへコピーされる間だけ待つ。
  • バッファに空きがなければ、送信側はバッファに空きができるまで待つ。

channel の操作

channel を作成する

channel は make ステートメントで作成する。

// バッファなし の int を送受信できる channel
ch0 := make(chan int)

// 10個のバッファを持つ T 型を送受信できる channel
ch1 := make(chan T, 10)

// バッファなし の int を送信のみできる channel
ch2 := make(chan<- int)

// バッファなし の int を受信のみできる channel
ch3 := make(<-chan int)

// nil channel
var ch4 chan int

channel にデータを送信する

// ch0 に 10 というデータを送信する
ch0 <- 10

channel を閉じる

close(ch0)

closeを呼び出し、事前に送信された値をすべて受信し終えた後で受信操作を行うと、そのチャネル型のゼロ値がブロックされることなしに ゼロ値が返されます。

受信専用の channel を close() するとエラーとなります。

channel からデータを受信する

// ch0 からデータを受信し、変数 x に格納する
x := <- ch0

// ch0 からデータを受信すると同時に ch0 が close されたか判定する x, ok := <- ch

nil channelからの受信は永久にブロックされます。

select 文で複数の channel からデータを受信する

func server(op binOp, service chan *request, quit chan bool) {
    for {
        select {
        case req := <-service:
            go run(op, req) // 待たない
        case <-quit:
            return
        }
    }
}

channel をセマフォのように使う

スループットを制限するようなケースで、バッファありチャネルをセマフォのように使うことができます。

var sem = make(chan int, MaxOutstanding)

func handle(r *Request) {
    sem <- 1    // アクティブキューの空き待ち
    process(r)  // 時間のかかる処理
    <-sem       // 完了。次のリクエストを処理可能にする
}

func Serve(queue chan *Request) {
    for {
        req := <-queue
        go handle(req)  // handleの終了待ちはしない
    }
}

0 件のコメント:

コメントを投稿