以下是有关无缓冲通道的简单示例代码:
ch01 := make(chan string)
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
fmt.Println("We are in the main goroutine")
ch01 <- "Hello"
我得到的结果:
We are in the main goroutine
We are in the sub goroutine
Hello
去游乐场: https://play.golang.org/p/rFWQbwXRzGw
根据我的理解,发送操作阻止了主goroutine,直到子goroutine在通道ch01
上执行了接收操作。程序退出了。
在发送操作之后放置sub goroutine之后:
fmt.Println("We are in the main goroutine")
ch01 <- "Hello"
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
发生了死锁:
We are in the main goroutine
fatal error: all goroutines are asleep - deadlock!
去操场
https://play.golang.org/p/DmRUiBG4UmZ
这次发生了什么?这是否意味着在ch01 <- "Hello"
之后主要的goroutine立即被封锁,以便sub goroutine没有机会跑?如果是真的,我应该如何理解第一个代码示例的结果?(首先在主goroutine中,然后在sub goroutine中)。
答案 0 :(得分:4)
发送时无缓冲的通道阻塞,直到接收器准备好读取。在您的第一个示例中,首先设置了一个阅读器,因此当发送时,它可以立即发送。
在你的第二个例子中,发送在接收器准备好之前发生,因此发送块和程序死锁。
您可以通过创建缓冲通道来修复第二个示例,但是有可能您无法看到goroutine的输出,因为程序可能会在刷新输出缓冲区之前退出(主goroutine)。在可以安排之前,goroutine甚至可能不会作为主要出口运行。
答案 1 :(得分:0)
首先,go-routines
同时运行。在第一个例子中,sub-goroutine已经启动,但是在第二个例子中,当发送操作出现时,go-routine还没有开始。
逐行思考。
在第一个示例中,sub-goroutine
已在主要运行例程中出现发送操作之前同时启动。结果,当发送操作发生时,已经存在接收器(sub-goroutine
)。
如果你调整第一个例子,
package main
import (
"fmt"
"time"
)
func main() {
ch01 := make(chan string)
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
// wait for start of sub-routine
time.Sleep(time.Second * 2)
fmt.Println("We are in the main goroutine")
ch01 <- "Hello"
// wait for the routine to receive and print the string
time.Sleep(time.Second * 2)
}
输出
We are in the sub goroutine
We are in the main goroutine
Hello
所以,你可以看到sub-goroutine已经启动了。它正在等待在频道上接收。当主goroutine在通道中发送字符串时,sub-goroutine恢复并接收信号。
但是在第二个例子中,程序已经停留在主程序send operation
中,并且子程序尚未启动并且不会启动,因为程序尚未获得该行。所以没有其他接收器接收信号。所以程序陷入僵局。
答案 2 :(得分:0)
对于无缓冲的通道,go例程将被阻止,直到没有人接收它为止。首先应该有一个go例程来从通道接收值,然后发送一个通道值。举例来说,当我们向通道发送一个值时,需要创建一个缓冲通道,以便将值保存到缓冲中,直到没有人接收它为止这样就可以了。
package main
import (
"fmt"
"time"
)
func main() {
ch01 := make(chan string, 10)
ch01 <- "Hello"
go func() {
fmt.Println("We are in the sub goroutine")
fmt.Println(<-ch01)
}()
fmt.Println("We are in the main goroutine")
time.Sleep(1 * time.Second)
}
答案 3 :(得分:0)
这是否意味着在ch01&lt; - &#34; Hello&#34;主要的goroutine立刻 阻止,以便sub goroutine没有机会跑?如果是真的, 我应该如何理解第一个代码示例的结果?(起初 在主要的goroutine,然后在sub goroutine)。
这是真的。你理解写的东西。未指定产生的goroutine的评估顺序,只能使用同步工具(通道,互斥体)进行控制。第一个示例中的子goroutine也可以在另一个环境中首先打印()。它只是未指定。