golang 是目前为止唯一一个在语言层面支持协程的编程语言。协程又被称为轻量级线程,具有资源占用低,调度速度快、轻量级等特点。也正因为如此,golang开发者可以更加方便的处理并发任务。生产-消费者模式作为一种经典的多线程设计模式,可以说是goper们最熟悉的并发处理模式。
在生产-消费者模式中,通常会通过一个单向channel传递消息,如果消费端因为未知错误导致panic退出,那么生产端将会阻塞,进而影响整个系统的运行。这个时候,如果我们没有正确处理异常或者输出崩溃信息,问题的排查将变得异常困难。
因此,在 golang 中开发生产-消费者模式的多线程任务时,保证消费端常驻协程的正常运行十分重要。在实际开发过程中踩了很多坑之后,我总结了一种基于 recover + 递归的方式,用于保证消费协程永远不会因panic而推出。具体方式如下:
var taskChan = make(chan bool)
func TaskConsumere() {
go func() {
defer func() {
if pErr := recover(); pErr != nil {
logger.Errorf("TaskConsumere panic:%+v", pErr)
logger.Errorf("TaskConsumere panic stack :%s", debug.Stack())
TaskConsumere()
}
}()
for {
select {
case <-conf.TaskChan:
// todo consumer process
}
}
}()
}