Go 性能优化技巧 4/10

qyuhen · · 3206 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

延迟调用(defer)确实是一种 “优雅” 机制。可简化代码,并确保即便发生 panic 依然会被执行。如将 panic/recover 比作 try/except,那么 defer 似乎可看做 finally。 如同异常保护被滥用一样,defer 被无限制使用的例子比比皆是。 ![defer](http://studygolang.qiniudn.com/160601/8732956ae01f52d537ffe21d6c39783d.jpg) ![defer_result](http://studygolang.qiniudn.com/160601/bcc28af226bcc78018b77cd9551037ee.jpg) 只需稍稍了解 defer 实现机制,就不难理解会有这样的性能差异。 编译器通过 runtime.deferproc “注册” 延迟调用,除目标函数地址外,还会复制相关参数(包括 receiver)。在函数返回前,执行 runtime.deferreturn 提取相关信息执行延迟调用。这其中的代价自然不是普通函数调用一条 CALL 指令所能比拟的。 ![defer2](http://studygolang.qiniudn.com/160601/959442b7fcc933298c48c855ab04792d.png) ![asm](http://studygolang.qiniudn.com/160601/d7cad45e58d5288e06bf452574031317.jpg) 或许你会觉得 4x 的性能差异算不得什么,但如果是下面这样呢? ![download](http://studygolang.qiniudn.com/160601/c47099a8dda6a77fca56201d4c23617e.png) 当多个 goroutine 执行该函数时,只怕性能差异就不是 4x,还得算上 httpGet 所需时间。原本的并发设计,因为错误的 defer 调用变成 “串行”。 与之类似的,还有下面这样的写法。 ![files](http://studygolang.qiniudn.com/160601/e898c7bc18c63db4a66c29db61b52c31.jpg) 如果 files 是个 “超大” 列表,只怕在 analysis 结束前,会有不小的隐式 “资源泄露”,这些不能及时回收的对象,会导致 GC 在内的相关性能问题。 解决方法么,要么去掉 f.close 前的 defer,要么将内层处理逻辑重构为独立函数(比如匿名函数调用)。 ![files2](http://studygolang.qiniudn.com/160601/9e0f87aeddad7eb64e71fc2e9603d0b1.jpg) 除此之外,单个函数里过多的 defer 调用可尝试合并。最起码,在并发竞争激烈时,mutex.Unlock 不应该使用 defer,而应尽快执行,仅保护最短的代码片段。

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3206 次点击  ∙  1 赞  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传