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

golang defer实现

derfer : 延迟调用,函数结束返回时执行,多个defer按照先进后出的顺序调用

原理:底层通过链表实现,每次新增的defer调用,通过头插法插入链表;defer执行时,从链表头开始遍历,相当于实现了后加入的defer先执行,先加的defer后执行

defer结构体

type _defer struct {started boolheap    bool// openDefer indicates that this _defer is for a frame with open-coded// defers. We have only one defer record for the entire frame (which may// currently have 0, 1, or more defers active).openDefer boolsp        uintptr // sp at time of deferpc        uintptr // pc at time of deferfn        func()  // can be nil for open-coded defers_panic    *_panic // panic that is running deferlink      *_defer // next defer on G; can point to either heap or stack!// If openDefer is true, the fields below record values about the stack// frame and associated function that has the open-coded defer(s). sp// above will be the sp for the frame, and pc will be address of the// deferreturn call in the function.fd   unsafe.Pointer // funcdata for the function associated with the framevarp uintptr        // value of varp for the stack frame// framepc is the current pc associated with the stack frame. Together,// with sp above (which is the sp associated with the stack frame),// framepc/sp can be used as pc/sp pair to continue a stack trace via// gentraceback().framepc uintptr
}

defer初始化

// Create a new deferred function fn, which has no arguments and results.
// The compiler turns a defer statement into a call to this.
func deferproc(fn func()) {gp := getg()if gp.m.curg != gp {// go code on the system stack can't deferthrow("defer on system stack")}d := newdefer()if d._panic != nil {throw("deferproc: d.panic != nil after newdefer")}// 这里使用头插法 插入链表d.link = gp._defergp._defer = dd.fn = fnd.pc = getcallerpc()// We must not be preempted between calling getcallersp and// storing it to d.sp because getcallersp's result is a// uintptr stack pointer.d.sp = getcallersp()// deferproc returns 0 normally.// a deferred func that stops a panic// makes the deferproc return 1.// the code the compiler generates always// checks the return value and jumps to the// end of the function if deferproc returns != 0.return0()// No code can go here - the C return register has// been set and must not be clobbered.
}

defer执行

func deferreturn() {gp := getg()for {d := gp._deferif d == nil {return}sp := getcallersp()if d.sp != sp {return}if d.openDefer {done := runOpenDeferFrame(gp, d)if !done {throw("unfinished open-coded defers in deferreturn")}gp._defer = d.linkfreedefer(d)// If this frame uses open defers, then this// must be the only defer record for the// frame, so we can just return.return}fn := d.fnd.fn = nil// 指向下一个defer节点gp._defer = d.linkfreedefer(d)fn()}
}

相关文章:

  • day02 VS Code开发单片机
  • web蓝桥杯真题:新鲜的蔬菜
  • 分表?分库?分库分表?实践详谈 ShardingSphere-JDBC
  • OpenAI Sora:浅析文生视频模型Sora以及技术原理简介
  • C语言奇技淫巧之--用宏定义替换函数名的另外一种思路
  • Android 属性动画及自定义3D旋转动画
  • C语言什么是指针? 什么是指针变量?
  • C++之STL整理(8)之stack用法(创建、赋值、增删查改)详解
  • 【Android】【root remount】【2】如何判断设备是否remount
  • 接口自动化测试(python+pytest+requests)
  • 工业视觉AI应用总结记录
  • AI日报:GPT-4-Turbo正式版自带读图能力;Gemini1.5Pro开放API;SD3将于4月中旬发布;抖音宫崎骏AI特效爆火
  • String类(1)
  • 动手学习深度学习(李沐)
  • Java项目:基于SSM+vue框架实现的人力资源管理系统设计与实现(源码+数据库+毕业论文+任务书)
  • 时间复杂度分析经典问题——最大子序列和
  • [译]如何构建服务器端web组件,为何要构建?
  • “大数据应用场景”之隔壁老王(连载四)
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • Android Studio:GIT提交项目到远程仓库
  • es6(二):字符串的扩展
  • java 多线程基础, 我觉得还是有必要看看的
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • laravel with 查询列表限制条数
  • mac修复ab及siege安装
  • Protobuf3语言指南
  • React Transition Group -- Transition 组件
  • SegmentFault 2015 Top Rank
  • Travix是如何部署应用程序到Kubernetes上的
  • 爱情 北京女病人
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 前端路由实现-history
  • 在electron中实现跨域请求,无需更改服务器端设置
  • k8s使用glusterfs实现动态持久化存储
  • 阿里云服务器如何修改远程端口?
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​力扣解法汇总946-验证栈序列
  • #pragma once
  • (31)对象的克隆
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (分布式缓存)Redis持久化
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (三)uboot源码分析
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (一)Linux+Windows下安装ffmpeg
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)关于pipe()的详细解析
  • (转载)OpenStack Hacker养成指南
  • ***php进行支付宝开发中return_url和notify_url的区别分析
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • *Django中的Ajax 纯js的书写样式1
  • .mysql secret在哪_MySQL如何使用索引