为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我需要用一个新的子程序运行 Walk?

为什么我需要用一个新的子程序运行 Walk?

Go
RISEBY 2021-08-16 19:11:34
我在 go 教程中编写了Walk 函数,该函数基本上是按顺序遍历树的。我有什么作品:package mainimport (    "fmt"    "code.google.com/p/go-tour/tree")// Walk walks the tree t sending all values// from the tree to the channel ch.func Walk__helper(t *tree.Tree, ch chan int) {    if (t == nil) {        return    }    Walk__helper(t.Left, ch)    ch <- t.Value    Walk__helper(t.Right, ch)}func Walk(t *tree.Tree, ch chan int) {    Walk__helper(t, ch)    close(ch)}func main() {    ch := make(chan int)    go Walk(tree.New(1), ch)    for v := range ch {        fmt.Println(v)       }}为什么我必须使用go Walk(tree.New(1), ch)而不仅仅是Walk(tree.New(1), ch)?我的印象是go关键字基本上会产生一个新线程。在这种情况下,我们会遇到问题,因为 for 循环可能会在子例程完成之前运行。奇怪的是,当我取出go关键字时,我陷入了僵局。这对我来说是相当违反直觉的。go关键字在这里到底是做什么的?
查看完整描述

1 回答

?
慕容3067478

TA贡献1773条经验 获得超3个赞

这里的关键点是range与通道耦合时。

当您range通过通道(在本例中为ch)时,它会等待项目在通道上发送,然后再遍历循环。这是一个安全的“阻塞”操作,在等待通道接收项目时不会死锁。

不使用 goroutine 时会发生死锁,因为您的通道没有缓冲。如果你不使用 goroutine,那么方法调用是同步的,Walk在通道上放一些东西......它会阻塞直到它被弹出。它永远不会弹出......因为方法调用是同步的。

我的印象是 go 关键字基本上会产生一个新线程

..那是不正确的。要了解那里发生的事情,还需要更多重要的实现细节。您应该将 goroutine 的思考过程与线程分开......并且将 goroutine 视为并发执行的一段代码,没有“线程”。


查看完整回答
反对 回复 2021-08-16
  • 1 回答
  • 0 关注
  • 220 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信