只改变一个字符使Go程序提速42%

go语言本来就以轻量快速著称,一位github员工却偶然发现:
只改变一个字符的位置,能把一段代码运行速度提高足足42%。
简直就像是……
这个简单有效的技巧一经发布,就引来众多程序员围观。
原作者自己也调侃,一般这种情况都是事先犯了个愚蠢的错误,后面才能提升这么大。
不过顺着这个思路发现有人发现,就连go开发团队的核心人物russ cox都在标准库中犯过同样的错误。
什么样的错误?
发现这个问题的harry在大型程序员交友平台github工作。
他在开发一个把github仓库中每个文件的所有者列出来的小工具。
功能很简单,就是根据codeowners文件中定义的规则匹配,写在越下面的规则优先级越高。
原理也很简单,就是从后往前一条一条处理,匹配到了就停止。
但就是这样一个简单的程序却出现了性能问题,处理中等大小的仓库就很慢了。
他打印出火焰图,发现大部分时间都花在了go语言的正则表达式引擎中。
另外在内存动态分配malloc和垃圾回收gc上面的花费也值得注意。
要减少malloc的时间,就需要用到go语言的逃逸分析(escape analysis)了。
简单来说,就是尽量把变量分配到栈上,让编译器自动管理内存的释放。
只有在“逃逸”也就是变量的作用域超出所在的栈时,才把变量分配到堆上,减轻运行时gc的压力。
在这次的程序中,harry确定了逃逸的变量是rule这个结构体(struct)。
但问题是,rule存储在ruleset这个切片(slice)里,按go语言的规则可以确信他已经在堆中了。
再分析一下代码,发现在给rule赋值的时候实际上是做了一次不必要的拷贝,后面用“&”取地址时候创建了一个逃逸的指针指向它的副本。
最后解决办法也很容易想出,只需要把&移动到上面。
这样就引用了切片中的结构体,避免了拷贝。
如何彻底避免?
在热议中,有网友分享了自己是怎么避免出现这个问题的。
对于每个结构体,把它看作纯值或纯指针,压根就不去使用&这种取地址的操作,避免隐式的内存分配。
如果你想要深入理解这个问题,也有人贴心的给出了需要提前了解的一些背景知识。
最后有人指出,rust语言为避免这个问题,直接规定必须显式操作才能拷贝一个数据结构。
当你不习惯的时候这规定烦得要命,但是总的来看还是值得。
方便or规范,你更倾向于哪种做法?


LED柔性灯带 8大不亮原因解析
软通动力朱健翔:抢抓科技革命机遇,已规划多种AI技术的应用场景
PowerPC,PowerPC是什么意思
价格战引爆智能音箱行业 语音交互设备将有更多形态
SM245 三态输出八路信号收发器
只改变一个字符使Go程序提速42%
车载单元中智能电源的设计
opencv 白平衡算法
中国联通“混改”的重头戏,员工股权激励计划方案
知用电流探头CP8050A产品规格及其应用
动力电池均衡仪在电动汽车中的应用-海瑞思
声音识别技术有什么应用
伺服电机和伺服驱动器区别
旁路电容、去耦电容及滤波电容的作用详解
创世界纪录 中国10比特光量子计算机诞生
中国移动咪咕联合央视新闻利用5G技术完成了阅兵高清直播
官方iPhone 11系列保护壳曝光,得知命名以及外观设计
针对Ampere Altra处理器的MongoDB优化指南
Opera优化底层代码,提速16%
如何利用物联网技术来追踪药品