golangでspawn, channel

前の投稿では、Crystalをやってみる
http://qiita.com/tabetomo/items/754308a6cd48bcf56585
elixirでspawn, channel
http://qiita.com/tabetomo/items/ef3e822e907ae0a37614
と言って、Crystalとelixir上のspawn（軽量スレッド）で送受信する例をやってみました。このページでは同じことをgolangでやってみます。

以下は、crystalでのプログラム例と実行例。

```crystal:spawn3.cr
ch1 = Channel(String).new(1)
ch2 = Channel(String).new(1)
done = Channel(Bool).new()

spawn do
  puts ch1.receive
  puts ch2.receive
  puts ch1.receive
  done.send(true) # end
end

spawn do
  ch1.send("apple")
  ch2.send("orange")
end
ch1.send("grape")

done.receive
```

```bash:terminal
$ crystall spawn3.cr                                                                  
grape                                                                                         
orange                                                                                        
apple 
```




# golangでspawn(go func)

あまりにあっけなく同じものがgoでかけてしまいました。crystalで書いた時も思いましたが、あっさりしすぎ。

```go:spawn3.go
package main
import "fmt"

func main() {
	ch1 := make(chan string, 1)
	ch2 := make(chan string, 1)
	done := make(chan bool, 0)
	go func() {
		msg := <-ch1
		fmt.Println(msg)
		msg = <-ch2
		fmt.Println(msg)
		msg = <-ch1
		fmt.Println(msg)
		done <- true
	}()
	go func() {
		ch1 <- "apple"
		ch2 <- "orange"
	}()
	ch1 <- "grape"
	<-done
}
```

実行例

```bash:terminal
$ go run spawn3.go                                                                   
grape                                                                                         
orange                                                                                        
apple 
```

備考；上記のプログラムですが、<-done　（ここでは、doneチャネルで何かを受け取るまで待つ）で待ちを入れないと、grape                                                                                      を表示した時点でプログラムが終わってしまいます。

# goでは、デッドロックするとエラー？

さて、最初crystalではサイズ０のチャネルでやっていました。

```crystal:spawn3.cr
ch1 = Channel(String).new
ch2 = Channel(String).new
略
```

この場合、チャネルを受信するまで送信の先に処理が進みません（逆に言えば、**受信されるまで送信側でブロックして待つ**ことができます）。チャネルのサイズを０にしてしまうと、上記プログラムはgrapeを表示してデッドロックします（Ctrl-Cで止めるまで処理が戻ってきません）。

が、前の投稿のコメント欄ではgoでは、エラーになる、とご指摘をいただいていました。**やってみよう**と思います。

```go:spawn3.go
package main
import "fmt"

func main() {
	ch1 := make(chan string, 0)
	ch2 := make(chan string, 0)
略
```

普通にgoでもサイズ０でstringのチャネルは作成可能でした（ビルドもできて動作もします）。ここまでは問題ないです。が、

実行例

```bash:terminal
$ go build spawn3.go
$ ./spawn3                                                                          
grape                                                                                         
fatal error: all goroutines are asleep - deadlock!                                            
                                                                                              
goroutine 1 [chan receive]:                                                                   
main.main()                                                                                   
        /Users/xxx/proj/go/src/github.com/tabetomo/contest/spawn3.go:23 +0x143          
                                                                                              
goroutine 5 [chan receive]:                                                                   
main.main.func1(0xc42001a0c0, 0xc42001a120, 0xc42001a180)                                     
        /Users/xxx/proj/go/src/github.com/tabetomo/contest/spawn3.go:12 +0x145          
created by main.main                                                                          
        /Users/xxx/proj/go/src/github.com/tabetomo/contest/spawn3.go:17 +0xbb           
                                                                                              
goroutine 6 [chan send]:                                                                      
main.main.func2(0xc42001a0c0, 0xc42001a120)                                                   
        /Users/xxx/proj/go/src/github.com/tabetomo/contest/spawn3.go:19 +0x5a           
created by main.main                                                                          
        /Users/xxx/proj/go/src/github.com/tabetomo/contest/spawn3.go:21 +0xe7 
```

のようにgoでは、grapeを表示した時点でデッドロックを検知（**fatal error: all goroutines are asleep - deadlock!**）して、実行時エラーになりました。これが良いのか悪いのかわかりませんが、all goroutines are asleepでは何もできない、ので、終わる方が良いのでしょう。