我正在学习Go,并且正在通过GoTours 学习此课程。到目前为止,这就是我所拥有的。
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(t *tree.Tree, ch chan int) { if t != nil { Walk(t.Left, ch) ch <- t.Value Walk(t.Right, ch) } } func main() { var ch chan int = make(chan int) go Walk(tree.New(1), ch) for c := range ch { fmt.Printf("%d ", c) } }
如您所见,我尝试通过打印输出到通道中的值来测试Walk函数。但是,出现以下错误。
1 2 3 4 5 6 7 8 9 10 throw: all goroutines are asleep - deadlock! goroutine 1 [chan receive]: main.main() main.go:25 +0x85 goroutine 2 [syscall]: created by runtime.main /usr/local/go/src/pkg/runtime/proc.c:221 exit status 2
我认为应该会出现此错误,因为我从不使用close该通道。但是,有没有一种方法可以“捕获”此死锁错误并以编程方式对其进行处理?
close
死锁类似于nil指针引用,它表示程序中的一个BUG。因此,此类错误通常无法恢复。
如lbonn所述,这里的问题是您需要“关闭(myChan)”您的频道。如果不执行此操作,则该范围将永远等待下一个元素。
您可以尝试如下操作:
func main() { var ch chan int = make(chan int) go func() { Walk(tree.New(1), ch) close(ch) }() for c := range ch { fmt.Printf("%d ", c) } }
如果要并行遍历树,则需要进行进一步的更改:
package main import ( "code.google.com/p/go-tour/tree" "fmt" "sync" ) // Walk walks the tree t sending all values // from the tree to the channel ch. func Walk(t *tree.Tree, ch chan int, done *sync.WaitGroup) { if t != nil { done.Add(2) go Walk(t.Left, ch, done) //look at each branch in parallel go Walk(t.Right, ch, done) ch <- t.Value } done.Done() } func main() { var ch chan int = make(chan int, 64) //note the buffer size go func() { done := new(sync.WaitGroup) done.Add(1) Walk(tree.New(1), ch, done) done.Wait() close(ch) }() for c := range ch { fmt.Printf("%d ", c) } }