【译】Go:程序如何恢复?
原文:https://medium.com/a-journey-with-go/go-how-does-a-program-recover-fbbbf27cc31e
当程序不能正确处理错误时, 会触发 Go 的 panic,比如无效的内存访问。如果错误时意外发生的,并且没有别的方法来处理它,开发人员也可以触发 panic。理解恢复或终止的流程有助于理解程序 panic 的后果。
多个函数帧
关于 panic 和 recover 有很多典型的例子和文档,包括 Go 博客中的 "Defer, Panic, and Recover"。让我们关注一个不同的例子,其中 panic 涉及到多个 defer 函数。下面是例子:
func main() {
defer println("defer 1")
level1()
}
func level1() {
defer println("defer func 3")
defer func() {
if err := recover(); err != nil {
println("recovering in progress...")
}
}()
defer println("defer 2")
level2()
}
func level2() {
defer println("defer func 4")
panic("foo")
}
这个程序由三个函数组成, 它们在链中被调用。一旦代码在最后一层 panic,Go将在主函数中运行这些 defer 函数:
在该阶段的中运行的代码没有恢复 panic, 然后 Go 构建父函数并且调用每个函数里的 defer
提醒一下,defer 函数是按照 后进先出(LIFO)的顺序执行的。关于 defer 函数内部信息,我建议你阅读 Go: How Does defer Statement Work?
由于一个其中一个函数可以恢复 panic,所以 Go 需要一种方法来跟踪它并恢复程序的执行。为此,每个 goroutine 都嵌入了一个特殊的属性,指向了代表 panic 的对象
当 panic 发生时,在运行 defer 函数之前创建该对象。然后,恢复 panic 的函数实际上只是返回该对象的信息,并将 panic 标记为已恢复
一旦发现 panic 已经恢复,Go需要继续当前的工作。然而,由于运行时是在 defer 中, 它不知道从哪里恢复,因此,当 panic 被标记为已恢复时,Go保存当前函数的程序计数器和堆栈指针,以便在发生 panic 之后恢复。
我们也可以用 objdump 检查程序计数器代表什么
(e.g. objdump -D my-binary | grep 105acef)
此指令指向函数调用 runtime.deferreturn
, 这是由编译器插入到每个函数末尾的指令,该指令运行 deferred 函数。在前面的例子中,它们中的大多数在恢复之前已经运行,因此在返回到调用者之前只有还没被调用的。
Wait Group
理解这个工作流向我们展示了defer函数的重要性,以及如何发挥作用,例如,在处理一组 goroutine 时,在 defer 函数中延迟对 WaitGroup 对象的调用可以防止死锁,这里有一个例子:
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer func() {
if err := recover(); err != nil {
println(err.(string))
}
}()
p()
wg.Done()
}()
wg.Wait()
}
func p() {
panic("foo")
}
这个程序会导致死锁,因为 wg.Done
永远不会被调用。将 wg.Done
移动到一个 defer 函数可以确保被调用,程序可以继续执行
Goexit
值得注意的是函数 runtime.Goexit
使用完全相同的工作流。它实际上创建了一个带有特殊标志的 panic 对象,以区别真正的 panic。此标志允许运行时跳过恢复并正确退出,而不是停止程序的执行。
【译】Go:程序如何恢复?的更多相关文章
- [译]好程序员的五声“呐喊”
通常编程情况下,会导致软件项目变坏的一些列反应 原文:The five shouts of good programmers 在任何一天,在这个世界上都有软件项目正在失败,这很常见.常见到当软件产品按 ...
- python学习笔记:"爬虫+有道词典"实现一个简单的英译汉程序
1.有道的翻译 网页:www.youdao.com Fig1 Fig2 Fig3 Fig4 再次点击"自动翻译"->选中'Network'->选中'第一项',如下: F ...
- eclipse代码恢复(开发程序代码恢复)
如果误操作,让本地代码丢失了不用怕,Eclipse local history可以恢复. 误删除文件后,直接ctrl+z可以恢复. 拉去代码覆盖了本地,也可以一个一个或者整体进行恢复:http://b ...
- [译]Java 程序员应该了解的 10 个面向对象设计原则
面向对象设计原则是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心,但大多数Java程序员追逐像Singleton.Decorator ...
- Ionic1 环境破坏后程序重新恢复过程
ionic platform remove android ionic platform add android cordova plugin add cordova-plugin-network-i ...
- Android清单文件详解(三)----应用程序的根节点<application>
<application>节点是AndroidManifest.xml文件中必须持有的一个节点,它包含在<manifest>节点下.通过<application>节 ...
- 如何定位Release 版本中程序崩溃的位置 ---利用map文件 拦截windows崩溃函数
1 案例描述 作为Windows程序员,平时最担心见到的事情可能就是程序发生了崩溃(异常),这时Windows会提示该程序执行了非法操作,即将关闭.请与您的供应商联系.呵呵,这句微软的“名 ...
- 小白学phoneGap《构建跨平台APP:phoneGap移动应用实战》连载四(使用程序载入事件)
在了解了PhoneGap中都有哪些事件之后,本节将開始对这些事件的使用方法进行具体地介绍.本节要介绍的是程序载入事件,也就是deviceready.pause和resume这3个事件. [范例4-2 ...
- java程序错误类型及异常处理
一.程序的错误类型 在程序设计中,无论规模是大是小,错误总是难免的.程序的设计很少有能够一次完成,没有错误的(不是指HelloWorld这样的程序,而是要实现一定的功能,具备一定实用价值的程序),在编 ...
随机推荐
- Linux权限问题(1)-Sticky
背景:朋友在使用php进行mv操作时,出现了权限被拒绝的问题.查看之后,发现目录设置了sticky权限,取消此权限后,文件可以正常mv及删除. Sticky:对于一个多人可写的目录,如果设置了stic ...
- Linux创建RAID概述
Linux创建RAID RAID概述 RAID(Redundant Array of Independent Disk)虚拟存储系统 RAID即独立冗余磁盘阵列,其思想是将多块独立的磁盘按不同的方式组 ...
- gitlab的CI/CD实现
环境准备: gitlab账号公网账号:代码仓库和编译器 目标机:装有docker和gitlab-runner环境的服务器(Linux或类unix机器,我使用的时centos 项目代码:testgola ...
- VMware安装RedHat7、CentOS7后无网卡解决办法
由于Vmware虚拟网卡和linux兼容问题导致驱动无法正常安装,默认的网卡类型不兼容找到我们的Vmware虚拟机文件夹,将VMware 虚拟机配置 (.vmx),追加一条设置,网卡类型etherne ...
- Linux 忘记密码解决方法——RedHat
[RedHat7.4版本] 1.将忘记密码的rhel7.4版本的虚拟机打开 2.等3秒左右出现这个画面时,用方向键,将光标移动到第二栏处,接着按"e"键 3.接在在linux16这 ...
- Linux_进程管理的基本概述
一.进程的基本概述 1️⃣:进程是已启动的可执行程序的运行中实例 2️⃣:/proc目录下以数字为名的目录,每一个目录代表一个进程,保存着进程的属性信息 3️⃣:每一个进程的PID是唯一的,就算进程退 ...
- 运维常用shell脚本二(压缩文件、过滤不需要的文件、检测进程)
一.压缩指定目录下的文件并删除原文件 #!/bin/bashZIP_DAY=7 function zip { local dir=$1 if [ -d $dir ];then local file_n ...
- CSS 重置技术
元素默认样式显示问题 每个浏览器对不同元素都有自己的默认样式.Google Chrome 渲染正文标题.段落.列表等,与 IE 浏览器可能都有所不同.这就导致同一个页面元素在不同的浏览器中显示效果不一 ...
- html原生js实现99乘法表
原生的js实现99乘法表实现选择下拉框颜色,改变背景颜色为选中的颜色 <!DOCTYPE html> <html> <head> <meta charset= ...
- Django(43)restful接口规范
restful接口规范 什么是接口规范?接口规范就是为了采用不同的后台语言,也能使用同样的接口获取到同样的数据.如何写接口:接口规范是规范化书写接口的,写接口要写url.响应数据 注:如果将 ...