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

时间:2014-09-18 23:18:27

标签: go

我正在编写基本遍历树的Walk function in the go tutorial。我的工作是什么:

package main

import (
    "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 个答案:

答案 0 :(得分:4)

当与频道结合时,此处的关键点是range

当你range通过一个频道(在这种情况下,ch)时,它会在迭代循环之前等待频道上的项目发送。这是一个安全的,阻止&#34;动作,在等待频道接收项目时不会死锁。

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

  

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

..这是不正确的。需要了解更多重要的实施细节才能了解其中发生的情况。您应该将goroutine的思维过程与线程分开..只需将goroutine视为同时执行的代码段,而不是&#34;线程&#34;。