Go语言:Go 语言之 defer 的前世今生
本文插图
作者 | 欧长坤
来源 | 码农桃花源
延迟语句 defer 在最早期的 Go 语言设计中并不存在 , 后来才单独增加了这一特性 , 由 Robert Griesemer 完成语言规范的编写 [Griesemer, 2009] ,并由 Ken Thompson 完成最早期的实现 [Thompson, 2009] , 两人合作完成这一语言特性 。
defer 的语义表明 , 它会在函数返回、产生恐慌或者 runtime.Goexit 时被调用 。 直觉上看 , defer 应该由编译器直接将需要的函数调用插入到该调用的地方 , 似乎是一个编译期特性 , 不应该存在运行时性能问题 , 非常类似于 C++ 的 RAII 范式(当离开资源的作用域时 , 自动执行析构函数) 。 但实际情况是 , 由于 defer 并没有与其依赖资源挂钩 , 也允许在条件、循环语句中出现 , 从而不再是一个作用域相关的概念 , 这就是使得 defer 的语义变得相对复杂 。 在一些复杂情况下 , 无法在编译期决定存在多少个 defer 调用 。
例如 , 在一个执行次数不确定的 for 循环中 , defer 的执行次数是随机的:
1func randomDefers {2 rand.Seed(time.Now.UnixNano)3 for rand.Intn(100) > 42 {4 defer func {5 println("changkun.de/golang")6 }7 }8}
因而 defer 并不是免费的午餐 , 在一个复杂的调用中 , 当无法直接确定需要的产生的延迟调用的数量时 , 延迟语句将导致运行性能的下降 。 本文我们来讨论 defer 的实现本质及其对症下药的相关性能优化手段 。
- defer 的类型
- 在堆上分配的 defer
- 编译阶段
- 运行阶段
- 在栈上创建 defer
- 开放编码式 defer
- 产生条件
- 延迟比特
- defer 的优化之路
- 小结
- 进一步阅读的参考文献
本文插图
defer 的类型 延迟语句的文法产生式 DeferStmt -> "defer" Expression 的描述非常的简单 , 因而也很容易将其处理为语法树的形式 , 但我们这里更关心的其实是它语义背后的中间和目标代码的形式 。
在 《Go 语言原本》Go 程序编译流程 一节中我们提到过 , 在进行中间代码生成阶段 , 会通过 compileSSA 先调用 buildssa 为函数体生成 SSA 形式的函数 , 而后调用 genssa 将函数的 SSA 中间表示转换为具体的指令 。
Go 语言的语句在执行 buildssa 阶段中 , 会由 state.stmt 完成函数中各个语句的 SSA 处理 。
1// src/cmd/compile/internal/gc/ssa.go2func buildssa(fn *Node, worker int) *ssa.Func {3 var s state4 ...5 s.stmtList(fn.Nbody)6 ...7}8func (s *state) stmtList(l Nodes) {9 for _, n := range l.Slice { s.stmt(n) }10}
对于延迟语句而言 , 其中间表示会产生三种不同的延迟形式 ,第一种是最一般情况下的在堆上分配的延迟语句 , 第二种是允许在栈上分配的延迟语句 , 最后一种则是**开放编码式(Open-coded)**的延迟语句 。 1// src/cmd/compile/internal/gc/ssa.go2func (s *state) stmt(n *Node) {3 ...4 switch n.Op {5 case ODEFER:6 // 开放编码式 defer7 if s.hasOpenDefers {8 s.openDeferRecord(n.Left)9 } else {10 // 堆上分配的 defer11 d := callDefer12 if n.Esc == EscNever {13 // 栈上分配的 defer14 d = callDeferStack15 }16 s.call(n.Left, d)17 }18 case ...19 }20 ...21}
- 【手机中国】华为又一项黑科技即将来临:可即时翻译任何动物语言
- [动物]兽语十级:华为愚人节成功研制出“动物语言翻译机”
- 上线■商务印书馆语言资源知识服务平台上线
- [C语言]Cu002FC++中的内存四区
- 汇编语言■C|编程的一些前置知识及底层(计算机组成与汇编)了解
- 【联合国】联合国最终确定了“6种”世界通用语言,日语的申请遭到拒绝!
- 净利润■主力洗盘之前,“盘口语言”都会出现这种征兆,看懂扭亏为盈!
- 「C语言」学了这么久的C语言,你真的懂scanf函数么?
- 『华为Mate30』华为推出国际版语音助手Celia:P40已预装、能听说三门语言
- 「编程语言」2020年,5 种 将死的编程语言