Go 性能优化技巧 4/10
2016-07-12 00:00
246 查看
延迟调用(defer)确实是一种 “优雅” 机制。可简化代码,并确保即便发生 panic 依然会被执行。如将 panic/recover 比作 try/except,那么 defer 似乎可看做 finally。
如同异常保护被滥用一样,defer 被无限制使用的例子比比皆是。
![](http://studygolang.qiniudn.com/160601/8732956ae01f52d537ffe21d6c39783d.jpg)
![](http://studygolang.qiniudn.com/160601/bcc28af226bcc78018b77cd9551037ee.jpg)
只需稍稍了解 defer 实现机制,就不难理解会有这样的性能差异。
编译器通过 runtime.deferproc “注册” 延迟调用,除目标函数地址外,还会复制相关参数(包括 receiver)。在函数返回前,执行 runtime.deferreturn 提取相关信息执行延迟调用。这其中的代价自然不是普通函数调用一条 CALL 指令所能比拟的。
![](http://studygolang.qiniudn.com/160601/959442b7fcc933298c48c855ab04792d.png)
![](http://studygolang.qiniudn.com/160601/d7cad45e58d5288e06bf452574031317.jpg)
或许你会觉得 4x 的性能差异算不得什么,但如果是下面这样呢?
![](http://studygolang.qiniudn.com/160601/c47099a8dda6a77fca56201d4c23617e.png)
当多个 goroutine 执行该函数时,只怕性能差异就不是 4x,还得算上 httpGet 所需时间。原本的并发设计,因为错误的 defer 调用变成 “串行”。
与之类似的,还有下面这样的写法。
![](http://studygolang.qiniudn.com/160601/e898c7bc18c63db4a66c29db61b52c31.jpg)
如果 files 是个 “超大” 列表,只怕在 analysis 结束前,会有不小的隐式 “资源泄露”,这些不能及时回收的对象,会导致 GC 在内的相关性能问题。
解决方法么,要么去掉 f.close 前的 defer,要么将内层处理逻辑重构为独立函数(比如匿名函数调用)。
![](http://studygolang.qiniudn.com/160601/9e0f87aeddad7eb64e71fc2e9603d0b1.jpg)
除此之外,单个函数里过多的 defer 调用可尝试合并。最起码,在并发竞争激烈时,mutex.Unlock 不应该使用 defer,而应尽快执行,仅保护最短的代码片段。
如同异常保护被滥用一样,defer 被无限制使用的例子比比皆是。
![](http://studygolang.qiniudn.com/160601/8732956ae01f52d537ffe21d6c39783d.jpg)
![](http://studygolang.qiniudn.com/160601/bcc28af226bcc78018b77cd9551037ee.jpg)
只需稍稍了解 defer 实现机制,就不难理解会有这样的性能差异。
编译器通过 runtime.deferproc “注册” 延迟调用,除目标函数地址外,还会复制相关参数(包括 receiver)。在函数返回前,执行 runtime.deferreturn 提取相关信息执行延迟调用。这其中的代价自然不是普通函数调用一条 CALL 指令所能比拟的。
![](http://studygolang.qiniudn.com/160601/959442b7fcc933298c48c855ab04792d.png)
![](http://studygolang.qiniudn.com/160601/d7cad45e58d5288e06bf452574031317.jpg)
或许你会觉得 4x 的性能差异算不得什么,但如果是下面这样呢?
![](http://studygolang.qiniudn.com/160601/c47099a8dda6a77fca56201d4c23617e.png)
当多个 goroutine 执行该函数时,只怕性能差异就不是 4x,还得算上 httpGet 所需时间。原本的并发设计,因为错误的 defer 调用变成 “串行”。
与之类似的,还有下面这样的写法。
![](http://studygolang.qiniudn.com/160601/e898c7bc18c63db4a66c29db61b52c31.jpg)
如果 files 是个 “超大” 列表,只怕在 analysis 结束前,会有不小的隐式 “资源泄露”,这些不能及时回收的对象,会导致 GC 在内的相关性能问题。
解决方法么,要么去掉 f.close 前的 defer,要么将内层处理逻辑重构为独立函数(比如匿名函数调用)。
![](http://studygolang.qiniudn.com/160601/9e0f87aeddad7eb64e71fc2e9603d0b1.jpg)
除此之外,单个函数里过多的 defer 调用可尝试合并。最起码,在并发竞争激烈时,mutex.Unlock 不应该使用 defer,而应尽快执行,仅保护最短的代码片段。
相关文章推荐
- Go 性能优化技巧 5/10
- Go 性能优化技巧 6/10
- Go 性能优化技巧 7/10
- Go 性能优化技巧 8/10
- HDU5546 Ancient Go DFS
- goldengate 学习有用网址
- GO的GDB调试
- 统一日志管理-Mongo 篇
- 大话设计模式(Golang) 二、策略模式
- Django开发环境的搭建
- golang学习之rpc实例
- 最新的黑客大杀器:Google Dorking
- mongoose
- Is it Google Hacking? It's Google Dorking
- 欢迎使用CSDN-markdown编辑器
- pycharm快捷键、配置virtualenv环境,配置django调试,配置远程调试
- Go语言_Go_Golang 逐行读取文件
- web流量/镜像复制工具——gor
- #include<algorithm>里的函数
- 终于又弄完一个DJANGO BY EXAMPLE的测试