内容简介:紧接前一篇在Go1.14之前,Go中的每一个defer函数,会在编译期在defer位置生成一个如下代码:
紧接前一篇 《Go1.14为time.Timer定时器带来巨幅性能提升》 ,本文介绍 Go 1.14针对defer做的优化。
在Go1.14之前,Go中的每一个defer函数,会在编译期在defer位置生成一个 runtime.deferproc
调用,并且在包含defer的函数退出时生成一个 runtime.deferreturn
调用。
如下代码:
0: func run() { 1: defer foo() 2: defer bar() 3: 4: fmt.Println("hello") 5: }
编译器会生成类似如下的代码:
runtime.deferproc(foo) // generated for line 1 runtime.deferproc(bar) // generated for line 2 fmt.Println("hello") runtime.deferreturn() // generated for line 5
这使得使用defer时增加了Go runtime函数调用开销。
另外值得一提的是,Go runtime中使用了先进后出的栈管理着一个函数中的多个defer调用,这也意味着defer越多,开销越大。
拿我们常见的互斥锁场景举例:
var mu sync.Mutex mu.Lock() defer mu.Unlock()
defer和非defer版本的benchmark如下:
BenchmarkMutexNotDeferred-8 125341258 9.55 ns/op 0 B/op 0 allocs/op BenchmarkMutexDeferred-8 45980846 26.6 ns/op 0 B/op 0 allocs/op
尽管耗时都是纳秒级别,但是defer版本是非defer版本的2.7倍,换句话说,在一些简单的锁场景,defer的开销甚至超过了锁自身的开销。如果在性能热点路径上,这部分开销还是挺可观的。
这使得部分Go程序员在高性能编程场景下,舍弃了defer的使用。但是不使用defer,容易导致代码可读性下降,资源忘记释放的问题。
于是在Go1.14,编译器会在某些场景下尝试在函数返回处直接调用被defer的函数,从而使得使用defer的开销就像一个常规函数调用一样。
还拿上面那个例子举例,编译器将生成如下的代码:
fmt.Println("hello") bar() // generated for line 5 foo() // generated for line 5
但是defer并不是所有场景都能内联。比如如果是在一个循环次数可变的循环中使用defer就没法内联。但是在函数起始处,或者不包含在循环内部的条件分支中的defer都是可以内联的。老实说,我们大部分时候也就是在这些简单场景使用defer。
在Go1.14beta再次执行上面mutex的基准测试:
BenchmarkMutexNotDeferred-8 123710856 9.64 ns/op 0 B/op 0 allocs/op BenchmarkMutexDeferred-8 104815354 11.5 ns/op 0 B/op 0 allocs/op
可以看到defer版本从 26.6 ns/op
下降到了 11.5
,与非defer版本的 9.64
已经非常接近了,性能确实有大幅提升。
本文内容来自一篇英文文章,但是省去了原文中关于defer的基础功能介绍,只对defer内联部分的内容进行意译,没有逐字翻译,感兴趣的可以观看原文: https://rakyll.org/inlined-defers/
Go 内联defe的设计、提案: https://github.com/golang/proposal/blob/master/design/34481-opencoded-defers.md
原文链接: https://pengrl.com/p/20023/
原文出处: yoko blog ( https://pengrl.com )
原文作者: yoko ( https://github.com/q191201771 )
版权声明:本文欢迎任何形式转载,转载时完整保留本声明信息(包含原文链接、原文出处、原文作者、版权声明)即可。本文后续所有修改都会第一时间在原始地址更新。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- [译] Go 1.14 将内联 defer 提高性能
- Go 1.14 巨大的性能是怎么实现的?主要关注 time.Timer 和 内联 defer
- Go1.14 巨大的性能是怎么实现的?主要关注 time.Timer 和 内联 defer
- iframe内联框架之巧妙跨域
- 提升go编译器内联程度
- 智能合约基础语言(十):Solidity内联汇编
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。