内容简介:紧接前一篇在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内联汇编
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Release It!
Michael T. Nygard / Pragmatic Bookshelf / 2007-03-30 / USD 34.95
“Feature complete” is not the same as “production ready.” Whether it’s in Java, .NET, or Ruby on Rails, getting your application ready to ship is only half the battle. Did you design your system to......一起来看看 《Release It!》 这本书的介绍吧!