内容简介:推荐阅读
下面这部分是关于 Go 1.14为time.Timer定时器带来巨幅性能提升,原文:https://www.pengrl.com/p/20021/
先看标准库中的 time package benchmark 的指标变化:
Changes in the time package benchmarks: name old time/op new time/op delta AfterFunc-12 1.57ms ± 1% 0.07ms ± 1% -95.42% (p=0.000 n=10+8) After-12 1.63ms ± 3% 0.11ms ± 1% -93.54% (p=0.000 n=9+10) Stop-12 78.3µs ± 3% 73.6µs ± 3% -6.01% (p=0.000 n=9+10) SimultaneousAfterFunc-12 138µs ± 1% 111µs ± 1% -19.57% (p=0.000 n=10+9) StartStop-12 28.7µs ± 1% 31.5µs ± 5% +9.64% (p=0.000 n=10+7) Reset-12 6.78µs ± 1% 4.24µs ± 7% -37.45% (p=0.000 n=9+10) Sleep-12 183µs ± 1% 125µs ± 1% -31.67% (p=0.000 n=10+9) Ticker-12 5.40ms ± 2% 0.03ms ± 1% -99.43% (p=0.000 n=10+10) Sub-12 114ns ± 1% 113ns ± 3% ~ (p=0.069 n=9+10) Now-12 37.2ns ± 1% 36.8ns ± 3% ~ (p=0.287 n=8+8) NowUnixNano-12 38.1ns ± 2% 37.4ns ± 3% -1.87% (p=0.020 n=10+9) Format-12 252ns ± 2% 195ns ± 3% -22.61% (p=0.000 n=9+10) FormatNow-12 234ns ± 1% 177ns ± 2% -24.34% (p=0.000 n=10+10) MarshalJSON-12 320ns ± 2% 250ns ± 0% -21.94% (p=0.000 n=8+8) MarshalText-12 320ns ± 2% 245ns ± 2% -23.30% (p=0.000 n=9+10) Parse-12 206ns ± 2% 208ns ± 4% ~ (p=0.084 n=10+10) ParseDuration-12 89.1ns ± 1% 86.6ns ± 3% -2.78% (p=0.000 n=10+10) Hour-12 4.43ns ± 2% 4.46ns ± 1% ~ (p=0.324 n=10+8) Second-12 4.47ns ± 1% 4.40ns ± 3% ~ (p=0.145 n=9+10) Year-12 14.6ns ± 1% 14.7ns ± 2% ~ (p=0.112 n=9+9) Day-12 20.1ns ± 3% 20.2ns ± 1% ~ (p=0.404 n=10+9)
数据来源:https://github.com/golang/go/commit/6becb033341602f2df9d7c55cc23e64b925bbee2
从基准测试结果中可以看到,After函数从老版本的1.63ms直接下降到了0.11ms,提升相当恐怖。
我个人对于此次优化的粗浅理解是:
在1.14之前,标准库会在在创建Timer时懒创建goroutinue,全局最多创建64个,这些goroutinue创建好后永远不会退出,每个goroutinue中有一个最小堆,管理着一部分定时器,这些goroutinue会给Go的线程调度模型带来非常大的开销。
而1.14则直接在P上管理Timer,这样调度器在每次调度循环的间隙都可以检查是否有超时的timer需要执行,并且可以通过netpoll进行唤醒,有点类似于epoll的事件驱动模型中的定时器管理。
具体的分析可以看欧长坤大佬对于Go 1.14定时器优化的分析:
-
Go夜读:第 74 期 time.Timer 源码分析 (Go 1.14) #541 https://github.com/developer-learning/night-reading-go/issues/541
-
相关的文章:17.2 time 的计时器 Timer | Go Under The Hood https://changkun.de/golang/zh-cn/part4lib/ch17other/time/
-
Go夜读在b站的视频:#74 Go time.Timer 源码分析(Go1.14)https://www.bilibili.com/video/av81849820
接着讲解 Go1.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
推荐阅读
喜欢本文的朋友,欢迎关注“ Go语言中文网 ” :
Go 语言中 文网启用 微 信学习交流群,欢迎加微信 : 274768166
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- [译] Go1.14将内联defer提高性能
- [译] Go 1.14 将内联 defer 提高性能
- Go 1.14 巨大的性能是怎么实现的?主要关注 time.Timer 和 内联 defer
- iframe内联框架之巧妙跨域
- 提升go编译器内联程度
- 智能合约基础语言(十):Solidity内联汇编
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
jQuery基础教程
Jonathan Chaffer、Karl Swedberg / 李松峰、卢玉平 / 人民邮电出版社 / 2009-11 / 49.00元
《jQuery基础教程(第2版)》作为《jQuery基础教程》的升级版,涵盖了jQuery 1.3的全部新特性,特别是新增了介绍jQuery UI(jQuery官方用户界面插件库)的内容。《jQuery基础教程(第2版)》前6章以通俗易懂的方式介绍了jQuery的基本概念,主要包括jQuery的选择符、事件、效果、DOM操作、AJAX支持等。随后3章从理论到实践,通过表格操作、构建功能型表单、实现......一起来看看 《jQuery基础教程》 这本书的介绍吧!