先看标准库中的time package benchmark的指标变化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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定时器优化的分析:
本文完,作者yoko,尊重劳动人民成果,转载请注明原文出处: https://pengrl.com/p/20021/