DRYな備忘録

Don't Repeat Yourself.

Go言語のchannelについてわかったことをメモるよ【golang】

問題

以前 Go言語のchannelって一体何よ ~基礎編~【golang】 - DRYな備忘録 のエントリを書いて分かった気になってたgolangchanですが、このたびそらで書いてみて動いたのでこれはちょっと理解できたと思っていいだろうということでメモるよ。

並行処理とは?

複数のマイクロプロセッサなどに処理を分散して割り当て、同時に計算・処理を行うことで、システム全体の処理性能を向上させる技術。また、そのような環境を効率的に活用するためのソフトウェアやプログラミングの手法の総称。

並列処理とは 〔 パラレルプロセッシング 〕 【 parallel processing 】 - 意味/解説/説明/定義 : IT用語辞典

メインの処理を止めることなく、別の場所で並行して処理をすることで、非同期で処理できたり、メインから複数の処理を同時にできたりする

Go言語の並行処理goroutine

Go言語では言語で並行処理へのアプローチを用意してくれていて、超簡単に並行処理が書ける。それがgoroutine(「ゴルーチン」と呼んでる人がいてわさわさするんだけど、「ゴールーチン」でいいんだよね?)

以下、例

package main

import "fmt"
import "time"

func myRoutine(mess string) {
    fmt.Printf(
        "ルーチンが%sを受け取ったお(^ω^ ≡ ^ω^)\n", mess,
    )
}

func main() {
    // goステートメントに関数を渡すだけで
    // goroutineがつくられる
    go myRoutine("hoge")
    go myRoutine("fuga")
 
    // goroutineはmainが死ぬと死ぬので
    // とりあえずmainを延命するよ
    time.Sleep(1 * time.Second)
    fmt.Println("Main \(^o^)/")
}

Try here! : Go Playground

並行処理あるある

  • 並行して走る処理が複数あると、単一のリソースに対する競合が発生する

f:id:otiai10:20140427115047p:plain

上記の例だと、リソースXがどういう値なのか保証できない困った

Go言語にはchannelというのが用意されてる

上記の問題に対して、Go言語ではchannelというものを用意している。 channelは、(mainを含む)複数のgoroutineがお互いにメッセージングをするときに、共通の窓口、まさにチャネルとして動いてくれる。

package main

import "fmt"
import "time"

func listen(sender chan string) {

    log := make([]string, 3)
 
    // 与えられたチャネルからの受信を待つルーチンを生成
    // goステートメントに渡す関数は無名関数でも可
    go func() {
        // これは無限ループの書き方
        for {
            // 「受信を待つ」書式
            mess := <-sender
            // ここで受信するまで
            // このルーチンの処理は止まっている
         
            // 受信し次第、以下が動き出す
            log = append(log, mess)
            fmt.Printf("Got message: %v (%v)\n", mess, log)
        }
    }()// 無名関数のこれ忘れがち!
}
func main() {
    // stringを送受信できるチャネル
    sender := make(chan string)
 
    // チャネルを渡してgoroutineを立てる
    listen(sender)
 
    // チャネルに流し込んだりする
    sender <- "foo"
    sender <- "bar"
    sender <- "buz"
 
    time.Sleep(1 * time.Second)
    fmt.Println("Main \(^o^)/")
}

Try here! : Go Playground

参考になるサンプルとか

The Revel Web Framework for Goのサンプルの中にあるchatとかが結構参考になった。

% go get github.com/revel/revel
% vi $GOPATH/src/github.com/revel/revel/samples/chat/

でソースを見たりできる。

たぶんよくある使い方としては

  • グローバルなチャネルを宣言する
  • 適当に非同期で処理したい内容を書いたルーチンをgoして立てとく
  • ルーチンはグローバルなチャネルからの受信を待っている
  • mainプロセスからグローバルなチャネルにメッセージを送る
  • ルーチンが動く

みたいな感じだと思ふ。

雑感

これをまとめてる最中でもやっぱりまだ分からないことが多いので、引き続き触って書いて、勉強していきたい。

Go言語たのしい! ✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌



DRYな備忘録