如何在Golang中处理高并发请求异常_Golang recover与channel结合技巧
技术百科
P粉602998670
发布时间:2026-01-25
浏览: 次 recover必须在defer中调用才有效,普通调用无效;需在每个goroutine内单独defer recover;应通过带缓冲channel统一收集panic错误;recover无法捕获Goexit、系统信号或Cgo崩溃;recover后禁止继续执行原逻辑,仅可记录错误和清理资源。
recover 必须在 defer 中调用,否则无效
Go 的 recover 只有在 panic 正在发生、且当前 goroutine 尚未退出时才有效。如果写成普通函数调用(比如放在逻辑中间),它什么也抓不到。必须配合 defer 才能拦截 panic —— 这是绝大多数新手踩的第一个坑。
常见错误写法:
func handleRequest() {
recover() // ❌ 永远返回 nil
panic("something went wrong")
}
正确姿势是:
- 每个可能 panic 的 goroutine 内部,都得有自己的
defer func() { recover() }() - 不要指望外层函数替内层 goroutine 拦截 panic —— goroutine 是独立的执行单元
- 如果用
go func() { ... }()启动,recover必须在该匿名函数内部 defer
用 channel 统一收集 panic 错误,避免日志丢失
高并发下,成百上千个 goroutine 同时 panic,如果每个都直接打日志或写文件,容易触发 I/O 竞争甚至阻塞。更稳妥的做法是把错误信息发到一个带缓冲的 channel,由单独的“错误处理 goroutine”消费。
关键点:
- channel 缓冲区大小要合理,比如
make(chan error, 1000),防止生产者因满而阻塞 - 发送前检查 channel 是否已关闭(尤其在服务 shutdown 阶段)
- 接收端要用
for err := range ch,而不是单次,否则只处理第一个错误
示例结构:
var panicCh = make(chan error, 1000)func worker(id int) { defer func() { if r := recover(); r != nil { panicCh <- fmt.Errorf("worker %d panicked: %v", id, r) } }() // ... 实际业务逻辑,可能 panic }
// 单独启动一个 goroutine 处理 panic 日志 go func() { for err := range panicCh { log.Printf("PANIC captured: %v", err) } }()
recover 无法捕获 runtime.Goexit 或 syscall 退出
recover 只对 panic 有效。以下情况它完全无能为力:
-
runtime.Goexit():主动终止当前 goroutine,不触发 panic -
操作系统信号如
SIGKILL、SIGQUIT - C 代码中调用
exit(1)或发生段错误 - 被
context.DeadlineExceeded中断的 goroutine(本身不 panic)
所以不能把 recover 当成“万能兜底”。真正健壮的服务需要:
- 用
context控制超时和取消 - 对 Cgo 调用加额外保护(比如
signal.Notify捕获 SIGSEGV) - 进程级监控(如 systemd、supervisord)来拉起崩溃后的主 goroutine
不要在 recover 后继续执行原逻辑
有人会这么写:
defer func() {
if r := r
ecover(); r != nil {
log.Println("recovered:", r)
// 接着往下跑?❌
doNextStep() // 危险!栈已损坏,变量状态未知
}
}()
这是严重误区。panic 可能发生在任意位置,栈已部分展开,局部变量、锁、channel 状态都不可信。recover 后唯一安全的操作是:
- 记录错误
- 清理资源(如 close channel、unlock mutex)
- 返回或退出当前 goroutine
继续执行后续业务代码,大概率引发二次 panic 或数据错乱。高并发场景下这种“带伤运行”的 goroutine 很难定位,比直接崩溃更麻烦。
# 操作系统
# 放在
# 自己的
# 这是
# 很难
# 能把
# 第一个
# 人会
# 都不
# 要用
# go
# golang
# Error
# 并发
# 并发请求
# 栈
# igs
# signal
# red
# channel
# for
# 局部变量
# 成百上千
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- c++的位运算怎么用 与、或、异或、移位操作详解【
- Win11如何设置文件权限 Win11 NTFS文
- Win11怎么压缩文件 Win11自带压缩解压功能
- Python对象比较排序规则_集合使用说明【指导】
- 如何从 Go 的 map[string]inter
- Python装饰器复用技巧_通用能力解析【教程】
- c++怎么使用std::filesystem遍历文
- PHP接收参数值为空怎么办_判断和处理空参数方法说
- Windows10怎么用“讲述人”读屏辅助 Win
- Win11怎么关闭OneDrive同步_Win11
- Windows电脑如何进入安全模式?(多种按键方法
- Windows10电脑怎么设置文件权限_Win10
- 如何使用Golang搭建Web开发环境_快速启动H
- Win11怎么关闭边缘滑动手势_Windows11
- 如何在Golang中定义接口_抽象方法和多态实现
- php删除数据怎么清空表_truncate与del
- Win10如何更改电脑休眠时间_Windows10
- PHP主流架构如何处理会话管理_Session与C
- Win11搜索不到蓝牙耳机怎么办 Win11蓝牙驱
- Python与MongoDB NoSQL开发实战_
- Laravel 查询 JSON 列:高效筛选包含数
- Python文件和流处理指南_高效读写大体积数据文
- Windows如何拦截2345弹窗广告_Windo
- 如何在Golang中使用time处理时间_Gola
- php串口通信波特率怎么选_根据硬件手册设置正确波
- php订单日志怎么记录发货_php记录订单发货操作
- php中self::能调用子类重写的方法吗_静态绑
- c++的mutex和lock_guard如何使用
- mac怎么安装adb_MAC配置Android A
- Win11怎么关闭通知消息_屏蔽Windows 1
- How to Properly Use NumPy
- Python音视频处理高级项目教程_FFmpegP
- c++如何实现多态性_c++ 虚函数表原理与动态绑
- Go语言中正确反序列化多个同级XML元素为结构体切
- Win11如何连接Xbox手柄 Win11蓝牙连接
- 如何将文本文件中的竖排字符串转换为横排字符串
- Win10怎样安装Word样式库_Win10安装W
- Python 模块的 __name__ 属性如何由
- c++怎么使用std::unique实现去重_c+
- 如何使用Golang sort排序切片_Golan
- Win10怎样清理C盘浏览器缓存_Win10清理浏
- Win11无法安装软件怎么办_Win11解除应用安
- php订单日志怎么记录物流_php记录订单物流变更
- 使用类变量定义字符串常量时如何实现类型安全的 Li
- c++如何使用std::bind绑定函数参数_c+
- Win11怎么设置系统还原_Windows11系统
- PHP的Workerman对架构扩展有啥帮助_应用
- Win11怎么关闭键盘按键音_Win11禁用打字声
- Windows10无法识别USB设备描述符请求失败
- Go 中实现 Python urllib.quot


QQ客服