Go 并发和通道混乱
在 Go 中,并发允许使用 goroutine 并发执行多个任务。通道促进这些 goroutine 之间的通信。然而,理解并发性可能具有挑战性,尤其是在处理通道时。
考虑以下代码片段:
<code class="go">package main import "fmt" func display(msg string, c chan bool) { fmt.Println("display first message:", msg) c <- true } func sum(c chan bool) { sum := 0 for i := 0; i < 10000000000; i++ { sum++ } fmt.Println(sum) c <- true } func main() { c := make(chan bool) go display("hello", c) go sum(c) <-c }</code>
在这段代码中,我们创建了两个 goroutine:display 和 sum。 display goroutine 打印一条消息,向通道发送信号,然后等待响应。 sum goroutine 执行长时间计算,打印结果,并向通道发送信号。在主 goroutine 中,我们会阻塞,直到从通道接收到信号。
代码的预期输出是:
display first message: hello
但是,我们观察到程序打印了两条消息以及计算总和:
display first message: hello 10000000000
理解问题
问题的出现是由于 goroutine 调度的不确定性。 Go 中的调度器在未被阻塞的 goroutine 之间自由选择。在此示例中,调度程序可以在任何给定时间执行任何 goroutine。
一种可能的执行顺序是:
在这种情况下,在显示器发送信号之前打印总和,导致意外的输出。
解决方案
为了确保程序只打印消息并在计算总和之前退出,我们可以使用不同的方法:
<code class="go">func main() { result := make(chan string) go display("hello", result) go sum(result) fmt.Println(<-result) }</code>
在此修订版本中,结果通道携带单个值,即来自显示 goroutine 的消息。主 goroutine 现在打印来自通道的值,确保它在退出之前收到消息。
以上是为什么 Go 程序会在给定代码片段中的消息之前打印计算总和,即使主 Goroutine 会阻塞直到从通道接收到信号?的详细内容。更多信息请关注PHP中文网其他相关文章!