我正在学习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)
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我尝试通过打印出我写入频道的值来测试我的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
Run Code Online (Sandbox Code Playgroud)
我认为应该预料到这个错误,因为我从不close通道.但是,有没有办法可以"捕获"这个死锁错误并以编程方式处理它?
这种死锁是因为,range构造迭代直到通道关闭.
http://golang.org/ref/spec#For_statements
在这里,您需要在完全探索树时关闭通道或使用其他构造.
对于此示例,您知道树的大小为10,因此您可以简单地执行1到10的for循环,并在每次迭代时从通道读取一次.
死锁类似于nil指针deference,因为它代表程序中的BUG.由于这个原因,这类错误通常无法恢复.
正如lbonn所提到的,这里的问题是你需要"关闭(myChan)"你的频道.如果不执行for-range循环,则循环将永远等待下一个元素.
你可以尝试这样的事情:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
如果要并行遍历树,则需要进行进一步更改:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
925 次 |
| 最近记录: |