当前位置: 首页 > news >正文

go中 panicrecoverdefer机制

 go的defer机制-CSDN博客 

常见panic场景

  • 数组或切片越界,例如 s := make([]int, 3); fmt.Println(s[5]) 会引发 panic: runtime error: index out of range
  • 空指针调用,例如 var p *Person; fmt.Println(p.Name) 会引发 panic: runtime error: invalid memory address or nil pointer dereference
  • 过早关闭 HTTP 响应体,例如 resp, err := http.Get(url); defer resp.Body.Close(); if err != nil { return err } 会引发 panic: runtime error: invalid memory address or nil pointer dereference,因为如果 http.Get 出错,resp 可能是 nil
  • 除以零,例如 x := 0; y := 1 / x 会引发 panic: runtime error: integer divide by zero
  • 向已经关闭的 channel 发送或接收消息,例如 ch := make(chan int); close(ch); ch <- 1 会引发 panic: send on closed channel
  • 重复关闭 channel,例如 ch := make(chan int); close(ch); close(ch) 会引发 panic: close of closed channel
  • 关闭未初始化的 channel,例如 var ch chan int; close(ch) 会引发 panic: close of nil channel
  • 未初始化的 map,例如 var m map[string]int; m["key"] = 1 会引发 panic: assignment to entry in nil map

recover常用的场景

  • panic 只会触发当前 Goroutine 的 defer
  • recover 只有在 defer 中调用才会生效;
package mainimport "fmt"func main() {defer func() {if r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()fmt.Println("Before panic")panic("Something went wrong")fmt.Println("After panic") // This line will not be executed
}运行结果Before panic
Recovered from panic: Something went wrong

defer,recover,panic,goroutine之间有什么联系呢

recover的作用域,recover在什么时候才会起作用

recover什么时候有效

recover未在defer内使用,是不会起任何作用

func main() {if r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}fmt.Println("Before panic")panic("Something went wrong")fmt.Println("After panic") // This line will not be executed
}结果Before panic
panic: Something went wronggoroutine 1 [running]:
main.main()/Users/alan/GolandProjects/design-patterns/main.go:11 +0x78

recover必须搭配defer使用

recover在defer内使用才会起作用

package mainimport "fmt"func main() {defer func() {if r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()fmt.Println("Before panic")panic("Something went wrong")fmt.Println("After panic") // This line will not be executed
}运行结果Before panic
Recovered from panic: Something went wrong

recove的作用域

recover在父协程

举个例子,一般使用chan的时候都是要在发送测关闭chan,我们在接受者通过控制超时

让函数提前退出,子协程一秒钟后退出


func main() {test()time.Sleep(time.Second * 10)
}
func test() {defer func() {if r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()var ch = make(chan int)go get_data(ch)ctx, cancel := context.WithTimeout(context.Background(), time.Second)defer cancel()defer close(ch)select {case <-ch:returncase <-ctx.Done():return}
}
func get_data(ch chan int) {time.Sleep(time.Second * 2)ch <- 1
}

结果

我们发现没有recover住panic,子协程在test方法调用退出后,发生了panic,导致整个程序panic挂掉

recover,panic同子协程

相同的例子我们,我们在引起panic的协程内进行recover,结果函数正常recover后程序正常退出

func main() {test()time.Sleep(time.Second * 10)fmt.Println("时间到了 主函数也溜了")
}
func test() {defer func() {fmt.Println("test:我先溜了")}()var ch = make(chan int)go get_data(ch)ctx, cancel := context.WithTimeout(context.Background(), time.Second)defer cancel()defer close(ch)select {case <-ch:returncase <-ctx.Done():return}
}
func get_data(ch chan int) {defer func() {if r := recover(); r != nil {fmt.Println("Recovered from panic:", r)}}()time.Sleep(time.Second * 2)ch <- 1
}

结果

正确使用close关闭chan

recover在同级函数作用域下起效

引用

Go 语言踩坑记——panic 与 recover | 小米信息部技术团队

Go 语言 panic 和 recover 的原理 | Go 语言设计与实现

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • python构建一个web程序
  • 浪潮服务器NVME 硬盘通过 Intel VROC 做RAID
  • MySQL中处理JSON数据:大数据分析新方向,技术详解与应用场景
  • LabVIEW深度监测系统
  • 实验九:点阵屏实验
  • Linux云计算 |【第二阶段】SECURITY-DAY5
  • 零基础5分钟上手谷歌云GCP - 服务器自动扩展
  • Go 使用Redis安装、实例和基本操作
  • Redis数据类型
  • 【cocos creator】2.x里,使用3D射线碰撞检测
  • 通过proxy和普通模式实现单例
  • 简单的jar包重打包Failed to get nested archive for entry 报错处理
  • 数学建模学习(116):全面解析梯度下降算法及其在机器学习中的应用与优化
  • 【JS】不使用BigInt实现大整数相加
  • 视频智能分析平台烟火检测视频安防监控烟火算法识别应用方案
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • CentOS7简单部署NFS
  • django开发-定时任务的使用
  • Fundebug计费标准解释:事件数是如何定义的?
  • Laravel5.4 Queues队列学习
  • linux安装openssl、swoole等扩展的具体步骤
  • React+TypeScript入门
  • Spring Cloud(3) - 服务治理: Spring Cloud Eureka
  • 从重复到重用
  • 电商搜索引擎的架构设计和性能优化
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 解决iview多表头动态更改列元素发生的错误
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 首页查询功能的一次实现过程
  • 微信支付JSAPI,实测!终极方案
  • 在Mac OS X上安装 Ruby运行环境
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • ‌分布式计算技术与复杂算法优化:‌现代数据处理的基石
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • !!java web学习笔记(一到五)
  • ## 1.3.Git命令
  • $.ajax,axios,fetch三种ajax请求的区别
  • ( 10 )MySQL中的外键
  • (2)(2.10) LTM telemetry
  • (3)选择元素——(17)练习(Exercises)
  • (C语言)fread与fwrite详解
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (一)搭建springboot+vue前后端分离项目--前端vue搭建
  • (译)计算距离、方位和更多经纬度之间的点
  • **CI中自动类加载的用法总结
  • .aanva
  • .NET : 在VS2008中计算代码度量值
  • .net mvc 获取url中controller和action
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • /proc/vmstat 详解