golang反编译_【Golang】脱胎换骨的defer(一)

83991c6530f6ed1992a8c3f673e58a44.png

Go语言的defer是一个很方便的机制,能够把某些函数调用推迟到当前函数返回前才实际执行。我们可以很方便的用defer关闭一个打开的文件、释放一个Redis连接,或者解锁一个Mutex。而且Go语言在设计上保证,即使发生panic,所有的defer调用也能够被执行。不过多个defer函数是按照定义顺序倒序执行的。 我们在公众号有一篇文章:

【Golang】脱胎换骨的defer​mp.weixin.qq.com
32f5e7eaaa60bc8bb1d29573de064d12.png

内容有点儿多,篇幅有点儿长,所以在这里我们打算拆分成四篇文章,每一篇专注一两个主要问题,可能会好消化些吧~

(一) defer如何延迟,因何倒序?

(二) defer函数怎样传参?

(三) defer+闭包,再多套几层,你还hold住吗?

(四) 都说defer1.12性能有坑,那坑从何来?又该怎么填?

c8e1b007a131cd8c1f500459698d5e93.png
func f1() {defer A()// code to do something
}

像这样一段代码,在Go1.12中编译后的伪指令是这样的(源码结合反编译整理出的伪代码,帮助理解~_~):

func f1() {r := runtime.deferproc(0, A) // 经过recover返回时r为1,否则为0if r > 0 {goto ret}// code to do somethingruntime.deferreturn()return
ret:runtime.deferreturn()
}

其中与defer指令相关的有两个部分。第一部分是deferproc,它负责保存要执行的函数信息,我们称之为defer“注册”

func deferproc(siz int32, fn *funcval)

从函数原型来看,deferproc函数有两个参数,第一个是被注册的defer函数的参数加返回值共占多少字节;第二个参数是一个runtime.funcval结构体的指针,也就是一个Function Value。对Function Value感兴趣,可以看看这个:

网页链接​mp.weixin.qq.com
914486906b8feb40d2bae04e7bc72c55.png

与defer指令相关的第二部分就是deferreturn,它被编译器插入到函数返回以前调用,负责执行已经注册的defer函数。所以defer函数之所以能延迟到函数返回前执行,就是因为先注册,后调用。

201ef728c193be0c98a661a7abf59901.png

再来看看defer函数为什么会倒序执行。defer注册信息会保存到defer链表。每个goroutine在运行时都对应一个runtime.g结构体,其中有一个_defer字段,保存的就是defer链表的头指针。

aef8f758d6b132d803115a1dde343b68.png

deferproc新注册的defr信息会添加到链表头。deferreturn执行时也从链表头开始,所以defer才会表现为倒序执行。

355fba33e1cb4848ef306136be9d7a47.png

理解了这些,就可以继续细化,看看defer注册时保存了什么信息,defer链表中每个元素究竟是什么结构了。

731f7459df882e789310f93b2f96c61b.png
type _defer struct {siz       int32started   boolsp        uintptr // sp at time of deferpc        uintptrfn        *funcval_panic    *_panic // panic that is running deferlink      *_defer}

siz:由deferproc第一个参数传入,就是defer函数参数加返回值的总大小。这段空间会直接分配在_defer结构体后面,用于在注册时保存给defer函数传入的参数,并在执行时直接拷贝到defer函数的调用者栈上。

started :标识defer函数是否已经开始执行;

sp:就是注册defer函数的函数栈指针;

pc:是deferproc函数返回后要继续执行的指令地址;

fn:由deferproc的第二个参数传入,也就是被注册的defer函数;

_panic:是触发defer函数执行的panic指针,正常流程执行defer时它就是nil;

link:自然是链到之前注册的那个_defer结构体。

网页链接​mp.weixin.qq.com
3d679dc32f52521a73196e590f027cce.png

3e4765da4dee3fce6425d84bcaf2decb.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/357018.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cad填充图案乱理石_CAD软件中如何自定义CAD填充图案?

在使用浩辰CAD软件绘制完成图纸后,发现自己绘制的CAD图纸没有做好区域分割,显得特别乱。这个时候该怎么办呢?快试试CAD填充图案吧!接下来就由小编来给大家介绍一下浩辰CAD软件中自定义CAD填充图案的操作教程吧!浩辰CAD…

单例设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 ! 目录 …

ansi编码转换_8b/1b编码是个什么东东

使用串行比并行总线可以节省更多的布线空间,芯片、电缆等的尺寸可以做得更小,同时传输速率更高。但是,在很多数字系统如CPU、DSP、FPGA等内部,进行数据处理的最小单位都是Byte,即8个bit,如何把一个或多个By…

使用CSDN云服务搭建一个WordPress 个人站点(详细教程)

目录 前言 站点效果图 搭建服务的一些准备工作 第一步。进入到云服务我的账号模块,创建一个项目, 第二步,先免费领取一台云主机, 第三步,进入云主机控制台 搭建站点操作步骤 第一步,登录云主机 第二…

使用CSDN云服务搭建一个WordPress 个人站点(视频教程)

目录 前言 视频教程 文字版教程 云主机体验地址 官方文档 前言 六一儿童节体验了一下CSDN云主机相关的服务,感觉最近官方最近变化很大,业务范围很广,这里简单体验了一下云主机,给大家分享一点心得,希望对大家有所启…

石板切割问题c语言_岩知识 | 岩板切板有讲究,工艺问题要注意

岩板的火继续烧着,岩板的深加工厂在不断地增加着,岩板的深加工产品正在走向各个建筑项目,逐渐在受到很多项目的宠爱。岩板作为与天然石材完全不同的产品,其优越的理化性能在许多方面胜过天然石材,但也有其严重的不足。…

JavaScript测验题回顾-刷题笔记001

目录 1.我们可以在下列哪个 HTML 元素中放置 Javascript 代码?​编辑 2.写 "Hello World" 的正确 Javascript 语法是? 3.插入 Javacript 的正确位置是? 4.引用名为 "xxx.js" 的外部脚本的正确语法是? 5.如…

java 方法委托托管_Java Web托管选项流程图

java 方法委托托管我经常被问到的一个问题是在何处以及如何托管Java Web应用程序。 在带有嵌入式服务器的Eclipse中创建它很好,但是如何将它带给人们呢? 长期以来,对于发烧友的程序员一直没有答案。 只有昂贵和超大型的选择。 事情最近发生了…

react重新渲染菜单_React实现递归组件

前言今天来实现一个 React 的递归组件。具体的效果图如下:图片说明假设后端返回的数据如下:[{ id: 1, parent_id: 0, name: 广东省, children: [{ id: 2, parent_id: 1, name: 广州市, …

JavaScript测验——给代码添加注释---第一关

校验规则 创建一个//样式的注释, 被注释的文本至少要包含 5 个字符。 创建一个/* */样式的注释, 被注释的文本至少要包含 5 个字符。

举重设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 ! 目录 …

JavaScript测验——声明变量---第2关

校验规则 注意: 变量名称可以由数字、字母、美元符号$ 或者 下划线_组成,但是不能包含空格或者以数字为开头。 闯关: 使用var 关键字来创建一个名为salePrice的变量。

palapaweb怎样开启服务_为什么说微服务,要从前后端分离开始?一文带你揭秘深入微服务...

前言既要低头赶路,又要抬头望天,科技是为人服务的,任何技术背后都有更深层次的考量。之前的文章中咱们聊了很多微服务的相关内容,简而言之,微服务的本质,就是一种可以加速分工、促进合作的新协作机制。知其…

list集合

List集合 List集合的概述 有序集合(也称之为序列),用户可以精确的控制列表中的每个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素 与 Set 集合不同,列表通常允许重复的元素 List 集合的特点 有…

JavaScript测验——使用赋值运算符---第3关

校验规则 以上代码数值8被赋给变量myVar中,然后再次将变量myVar解析为8并将其赋给myNum变量。 闯关: 把数值6赋给变量 x。 然后把变量x中的内容赋给变量y。

antd table排序 vue_商品品牌业务之Vue编写前端页面

今天是刘小爱自学Java的第145天。感谢你的观看,谢谢你。学习计划安排如下:打算从前端页面到后台服务器代码完整地写一遍,但显然我高估了自己的实力,几个小时的时间根本不够用。并且因为教程和vue现在最新的组件用法不一样&#xf…

JavaScript测验——使用赋值运算符初始化变量---第4关

通常在声明变量的时候会给变量初始化一个初始值。 例如: var myVar 0; 以上代码创建一个名为myVar的变量并指定一个初始值0。

Zabbix-3.0.0 安装Graphtree

导读Zabbix中,想要集中展示图像,唯一的选择是screen,后来zatree解决了screen的问题,但性能不够好。Graphtree 由OneOaaS开发并开源出来,用来解决Zabbix的图形展示问题,性能较好。一、Graphtree功能概述集中…

装饰器设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。 在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 ! 目录 …

JavaScript测验——未初始化的变量---第5关

校验规则 当你用一个值是undefined的变量来做字符串拼接操作的时候,它会输出字符串"undefined"。 闯关: 定义 3 个变量a、b、c,并且分别给他们赋值:3、9、"I am pretty",这样它们值就不会是undefined了。