Go语言之defer的前世今生CSDN

作者

欧长坤

来源

码农桃花源

延迟语句defer在最早期的Go语言设计中并不存在,后来才单独增加了这一特性,由RobertGriesemer完成语言规范的编写[Griesemer,],并由KenThompson完成最早期的实现[Thompson,],两人合作完成这一语言特性。

defer的语义表明,它会在函数返回、产生恐慌或者runtime.Goexit时被调用。直觉上看,defer应该由编译器直接将需要的函数调用插入到该调用的地方,似乎是一个编译期特性,不应该存在运行时性能问题,非常类似于C++的RAII范式(当离开资源的作用域时,自动执行析构函数)。但实际情况是,由于defer并没有与其依赖资源挂钩,也允许在条件、循环语句中出现,从而不再是一个作用域相关的概念,这就是使得defer的语义变得相对复杂。在一些复杂情况下,无法在编译期决定存在多少个defer调用。

例如,在一个执行次数不确定的for循环中,defer的执行次数是随机的:

1funcrandomDefers(){2rand.Seed(time.Now().UnixNano())3forrand.Intn()42{4deferfunc(){5println(changkun.de/golang)6}()7}8}

因而defer并不是免费的午餐,在一个复杂的调用中,当无法直接确定需要的产生的延迟调用的数量时,延迟语句将导致运行性能的下降。本文我们来讨论defer的实现本质及其对症下药的相关性能优化手段。

defer的类型在堆上分配的defer编译阶段运行阶段在栈上创建defer开放编码式defer产生条件延迟比特defer的优化之路小结进一步阅读的参考文献

defer的类型

延迟语句的文法产生式DeferStmt-deferExpression的描述非常的简单,因而也很容易将其处理为语法树的形式,但我们这里更关心的其实是它语义背后的中间和目标代码的形式。

在《Go语言原本》Go程序编译流程一节中我们提到过,在进行中间代码生成阶段,会通过


转载请注明:http://www.aierlanlan.com/rzdk/7551.html

  • 上一篇文章:
  •   
  • 下一篇文章: