用Go语言进行 spawn(派生)和 channel(通道)的操作

在之前的帖子中,我尝试了Crystal。在这个链接中:http://qiita.com/tabetomo/items/754308a6cd48bcf56585
我试着用elixir的spawn和channel来进行发送和接收操作。现在我将用相同的方法在golang中尝试一下。

以下是Crystal编程示例和执行示例。

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
$ crystall spawn3.cr                                                                  
grape                                                                                         
orange                                                                                        
apple 

在Go中生成(goroutine)

同一件事情在go中的进行过程过于简单了。当我用crystal写的时候也有同样的感觉,太过轻松了。

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
}

实施案例

$ go run spawn3.go                                                                   
grape                                                                                         
orange                                                                                        
apple 

备注;关于上述程序,如果不加入等待(done)的话,在显示grape时程序会立即结束。

在Go语言中,发生死锁会产生错误吗?

好吧,一开始我们在crystal中使用尺寸为0的通道进行操作。

ch1 = Channel(String).new
ch2 = Channel(String).new

在这种情况下,直到接收到通道后,发送方的处理才能继续进行(换句话说,发送方可以阻塞并等待接收)。如果将通道的大小设为0,上述程序将显示”grape”并发生死锁(直到按下Ctrl-C之前,处理不会返回)。

然而,在之前的帖子评论中,有人指出使用”go”会导致错误。我打算试一下。

package main
import "fmt"

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

普通にgoでもサイズ0のstringチャネルを作成することができます(ビルドもできて動作もします)。ここまでは問題ありません。ただし、

执行实例

$ 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!)。我不知道这是好还是坏,但是当所有goroutines都处于休眠状态时,无法做任何处理,所以结束可能更好。