Arp*_*sss 3 go concurrent-programming goroutine
我想写三个并发的例程,它们相互发送整数.现在,我的代码被正确编译,但是在第一次执行之后它会给出错误"所有goroutines都睡着了 - 死锁!".我试图找到错误,但我无法在代码逻辑中找到任何错误.任何人都可以帮我找到我的代码的错误.我的代码如下.提前致谢.
package main
import "rand"
func Routine1(command12 chan int, response12 chan int, command13 chan int, response13 chan int) {
for i := 0; i < 10; i++ {
y := rand.Intn(10)
if y%2 == 0 {
command12 <- y
}
if y%2 != 0 {
command13 <- y
}
select {
case cmd1 := <-response12:
print(cmd1, " 1st\n")
case cmd2 := <-response13:
print(cmd2, " 1st\n")
}
}
close(command12)
}
func Routine2(command12 chan int, response12 chan int, command23 chan int, response23 chan int) {
for i := 0; i < 10; i++ {
select {
case x, open := <-command12:
{
if !open {
return
}
print(x, " 2nd\n")
}
case x, open := <-response23:
{
if !open {
return
}
print(x, " 2nd\n")
}
}
y := rand.Intn(10)
if y%2 == 0 {
response12 <- y
}
if y%2 != 0 {
command23 <- y
}
}
}
func Routine3(command13 chan int, response13 chan int, command23 chan int, response23 chan int) {
for i := 0; i < 10; i++ {
select {
case x, open := <-command13:
{
if !open {
return
}
print(x, " 2nd\n")
}
case x, open := <-command23:
{
if !open {
return
}
print(x, " 2nd\n")
}
}
y := rand.Intn(10)
if y%2 == 0 {
response13 <- y
}
if y%2 != 0 {
response23 <- y
}
}
}
func main() {
command12 := make(chan int)
response12 := make(chan int)
command13 := make(chan int)
response13 := make(chan int)
command23 := make(chan int)
response23 := make(chan int)
go Routine1(command12, response12, command13, response13)
go Routine2(command12, response12, command23, response23)
Routine3(command13, response13, command23, response23)
}
Run Code Online (Sandbox Code Playgroud)
谁能告诉我为什么如果我将Routine2和Routine3声明为常规,为什么输出为[无输出].我是GO的新手,根据我从" http://golang.org/doc/effective_go.html#concurrency " 了解到的,go用于与同一地址空间中的其他goroutine并行执行goroutine.那么,问题是,所有例程都在运行,但输出是[无输出].
为了使程序更清晰:实际上我要做的是在每两个例程之间创建两个通道,然后使用一个通道将int发送到其他通道,并通过该例程中的另一个通道接收int.例如,例程1和3通道之间是命令13和响应13.例程1使用command13发送int和response13以接收int到/来自例程3.例程3 response13用于发送int和command13以接收int到/来自例程1(命令/响应13表示例程1和3之间的通道).现在,由于三个例程是并发的,并且它们具有处理收到的消息或发送消息的特定例程,为什么它们会出现死锁?
go Routine1(command12, response12,command13, response13 )
go Routine2(command12, response12,command23, response23) // go routine
Routine3(command12, response12,command23, response23 )
Run Code Online (Sandbox Code Playgroud)
这将在一个新的goroutine中启动Routine1,主要的goroutine将继续下一个声明.因此,Routine1和Routine2将同时执行,但Routine3将在Routine2完成后启动.你可能会错过另一个"去"声明.
然后,我试图按照你的计划.在Routine1中你做到了
command13 <- y
Run Code Online (Sandbox Code Playgroud)
这将阻止Routine1,直到有另一个goroutine准备好,它能够接收你的消息.所以你需要y := <-command13另一个goroutine.
但现在,让我们仔细看看其他两个goroutines的参数:
Routine2(command12, response12,command23, response23)
Routine3(command12, response12,command23, response23 )
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,没有一个goroutine可以访问command13(但是您将两次传递command12).因此,Routine1,Routine2或Routine3都无法继续.僵局!
我建议你回到绘图板.考虑一下您首先要做的事情,绘制一些关于预期消息流的图表,然后尝试实现该行为.
此后调试程序真的很难,
response23到被调用的参数response13,依此类推.将它们混合起来非常容易.gofmt在你发布它之前,你的源代码是个好主意:)作为一个起点,我可以向你推荐Go教程中的"Prime Numbers"示例.在此示例中,可能的素数从一个goroutine传递到另一个goroutine.此外,这个例子还包含一些关于消息流的漂亮图形以及一些非常好的解释.你可能会喜欢它.