Golang 中 recover() 内发送错误到 channel 不生效问题排查
问题根因
- 你声明的
batchErrChan是无缓冲通道,无缓冲通道的发送操作会阻塞到有接收方准备好接收数据才能完成。当panic触发defer中的错误发送逻辑时,如果此时消费通道的goroutine还未调度到range接收的代码段,errchan <- errors.New("recover err")会永久阻塞,后续的close(batchErrChan)、wg.Done()都无法执行,主goroutine卡在wg.Wait()形成死锁。 - 就算发送操作刚好调度成功,发送完成后会立刻执行
close和wg.Done(),主goroutine的wg.Wait()会立刻返回,主程序直接退出,此时消费goroutine可能还没来得及执行打印逻辑就被强制终止,因此看不到输出。
修复方案
可以通过带缓冲通道+双等待组的方式解决,既避免发送阻塞,也能保证消费逻辑执行完成再退出程序:
package main import ( "fmt" "sync" "errors" ) func main() { var wg sync.WaitGroup var consumeWg sync.WaitGroup wg.Add(1) consumeWg.Add(1) // 改成带1个缓冲的通道,发送不需要等接收方就绪 batchErrChan := make(chan error, 1) go func(errchan chan error) { defer func() { if r := recover(); r != nil { errchan <- errors.New("recover err") } close(batchErrChan) wg.Done() }() panic("ddd") }(batchErrChan) go func() { defer consumeWg.Done() for _ = range batchErrChan { fmt.Println("err in range") } }() wg.Wait() // 等待消费协程执行完成再退出 consumeWg.Wait() }
内容的提问来源于stack exchange,提问作者Igor Batov
相关产品推荐
相关产品推荐

