Go言語ではゴルーチンという機能を使って並行処理が簡単に記述できます。さらにこの処理間で通信をするとき、チャンネルというものを通じてメッセージを通信することができます。
UNIXのパイプに似ていて、データの受信待ちのために処理をブロックするところが面白いと思いました。
ソースコード上で、送信と受信がわかりやすく記述でき、このあたりGo言語の特長的な部分です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
package main import ( "fmt" "time" "log" "math/rand" ) func worker() <-chan string { c := make(chan string,) for i := 0; i < 5; i++ { go func(i int) { r := rand.Intn(10) fmt.Println(r) time.Sleep(time.Duration(r) * time.Second) msg := fmt.Sprintf("%d) %ds", i, r) c <- msg // send message }(i) } return c } func main() { rand.Seed(time.Now().UnixNano()) c := worker() i := 0 for{ select{ case msg := <-c: // receive message log.Println(msg) i ++ if i >= 3 { return } case <-time.After(3 * time.Second): log.Println("Time Out") return } } } |
受信部分でselectが使われているのもC言語でソケットの変化を待つselectと似ています。
このプログラムは、ランダムで処理の時間が変化する5つの処理からメッセージが送られるのですが、そのうちの3つを受信するか、もしくは3秒でタイムアウトすると処理が終了するものです。
メッセージの送信がc <-msg、受信がmsg := <-c、タイムアウトの受信は、<-time.After です。
<-の部分で処理がブロックされます。ここではやっていませんが、送信も設定したバッファーサイズを上限にしてブロックできるようです。
以前、このブログでも書きましたが、Go-RoutineとChannelの組み合わせはCo-Routineに似ていてるところもあります。(名前も似ています)
やはり後から作られた言語の方が、このような新しい考え方、文法の実装は優位になりますが、逆に言えばこのような実装があるからこそ新しい言語に魅力を感じることができます。
参考: http://jxck.hatenablog.com/entry/20130414/1365960707