症状
某个 goroutine 卡住而无任何进展,进程可能打印 fatal error: all goroutines are asleep - deadlock!,也可能在还有其它 goroutine 存活时静默挂起。CPU 占用近乎为零,因为没有任何可运行的任务。
诊断
先确认 channel 在使用前已构造,然后导出 goroutine 栈:
kill -QUIT $(pgrep myapp)
栈信息会显示某个 goroutine 阻塞在特定行的 channel 收发上;据此回溯该 channel 变量的声明。
修复
务必在使用前 make,并为等待设置上限:
type Worker struct {
jobs chan int
}
func NewWorker() *Worker {
return &Worker{jobs: make(chan int, 8)}
}
func (w *Worker) run(ctx context.Context) {
select {
case job := <-w.jobs:
_ = job
case <-ctx.Done():
return
}
}
验证
以 -race 并带 context 超时运行。程序能正常结束,SIGQUIT 栈也再不会显示 goroutine 停在原先为 nil 的 channel 上。