跳到主要内容

14.6 协程和恢复 (recover)

一个用到 recover() 的程序(参见第 13.3 节停掉了服务器内部一个失败的协程而不影响其他协程的工作。

func server(workChan <-chan *Work) {
for work := range workChan {
go safelyDo(work) // start the goroutine for that work
}
}

func safelyDo(work *Work) {
defer func() {
if err := recover(); err != nil {
log.Printf("Work failed with %s in %v", err, work)
}
}()
do(work)
}

上边的代码,如果 do(work) 发生 panic(),错误会被记录且协程会退出并释放,而其他协程不受影响。

因为 recover() 总是返回 nil,除非直接在 defer 修饰的函数中调用,defer 修饰的代码可以调用那些自身可以使用 panic()recover() 避免失败的库例程(库函数)。举例,safelyDo()defer 修饰的函数可能在调用 recover() 之前就调用了一个 logging() 函数,panicking 状态不会影响 logging() 代码的运行。因为加入了恢复模式,函数 do()(以及它调用的任何东西)可以通过调用 panic() 来摆脱不好的情况。但是恢复是在 panicking 的协程内部的:不能被另外一个协程恢复。