一尘不染

如何捕获通道死锁的异常?

go

我正在学习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该通道。但是,有没有一种方法可以“捕获”此死锁错误并以编程方式对其进行处理?


阅读 327

收藏
2020-07-02

共1个答案

一尘不染

死锁类似于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)
    }
}
2020-07-02