我正在学习Go并正在GoTours工作this lesson。这是我到目前为止所拥有的。
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
频道。但是,有没有办法可以“捕获”这个死锁错误并以编程方式处理它?
答案 0 :(得分:7)
这种死锁是因为range
构造迭代直到通道关闭。
http://golang.org/ref/spec#For_statements
在这里,您需要在完全探索树时关闭通道或使用其他构造。
对于此示例,您知道树的大小为10,因此您可以简单地执行1到10的for循环,并在每次迭代时从通道读取一次。
答案 1 :(得分:6)
死锁类似于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)
}
}
如果要并行遍历树,则需要进行进一步更改:
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)
}
}
答案 2 :(得分:5)
不,你无法从僵局中恢复过来。
答案 3 :(得分:0)
通道死锁错误是:
致命错误:所有goroutine都在睡觉-死锁!
通道死锁不是{"schedule":"0 */5 * * * *"}
错误,而是致命错误,请参见https://golang.org/pkg/log/#Fatal
致命等同于Print(),然后调用os.Exit(1)。
如您所见,public static void MyFunction([TimerTrigger("0 */2 * * * *",
RunOnStartup = true)]
TimerInfo timerInfo,
TextWriter log)
最后会调用panic
,因此与Fatal
完全不同,这就是为什么不能os.Exit(1)
答案 4 :(得分:0)
我想出了这个解决方案,它基本上使用2个通道,并得出结论,如果两个通道都关闭,则树是相同的。
package main
import "golang.org/x/tour/tree"
import "fmt"
// 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 {
return
}
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
// Same determines whether the trees
// t1 and t2 contain the same values.
func Same(t1, t2 *tree.Tree) bool {
tc1 := make(chan int)
tc2 := make(chan int)
go func() {
Walk(t1, tc1)
close(tc1)
}()
go func() {
Walk(t2, tc2)
close(tc2)
}()
for {
x1, y1 := <-tc1;
x2, y2 := <-tc2;
if x1 != x2 {
return false
}
if !y1 || !y2 {
return true
}
}
}
func main() {
t1, t2 := tree.New(123), tree.New(1)
fmt.Println(Same(t1, t2))
}
我正在遵循导游指南,到目前为止只使用了所讲授的资源(与上述解决方案中使用同步包不同)。