0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

马哥Linux运维 来源:量子位 作者:量子位 2022-11-24 15:48 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

Go语言本来就以轻量快速著称,一位GitHub员工却偶然发现:

只改变一个字符的位置,能把一段代码运行速度提高足足42%。

e60973ee-6b35-11ed-8abf-dac502259ad0.png

简直就像是……

e61cb9cc-6b35-11ed-8abf-dac502259ad0.png

这个简单有效的技巧一经发布,就引来众多程序员围观。

原作者自己也调侃,一般这种情况都是事先犯了个愚蠢的错误,后面才能提升这么大。

不过顺着这个思路发现有人发现,就连Go开发团队的核心人物Russ Cox都在标准库中犯过同样的错误。

e62da426-6b35-11ed-8abf-dac502259ad0.png

什么样的错误?

发现这个问题的Harry在大型程序员交友平台GitHub工作。

他在开发一个把GitHub仓库中每个文件的所有者列出来的小工具。

功能很简单,就是根据CODEOWNERS文件中定义的规则匹配,写在越下面的规则优先级越高。

e6596aac-6b35-11ed-8abf-dac502259ad0.png

原理也很简单,就是从后往前一条一条处理,匹配到了就停止。

e66c4546-6b35-11ed-8abf-dac502259ad0.png

但就是这样一个简单的程序却出现了性能问题,处理中等大小的仓库就很慢了。

e6894498-6b35-11ed-8abf-dac502259ad0.png

他打印出火焰图,发现大部分时间都花在了Go语言的正则表达式引擎中。

另外在内存动态分配malloc和垃圾回收gc上面的花费也值得注意。

e69a928e-6b35-11ed-8abf-dac502259ad0.png

要减少malloc的时间,就需要用到Go语言的逃逸分析(Escape Analysis)了。

简单来说,就是尽量把变量分配到栈上,让编译器自动管理内存的释放。

只有在“逃逸”也就是变量的作用域超出所在的栈时,才把变量分配到堆上,减轻运行时GC的压力。

在这次的程序中,Harry确定了逃逸的变量是rule这个结构体(struct)。

e6ad0fcc-6b35-11ed-8abf-dac502259ad0.png

但问题是,rule存储在RuleSet这个切片(slice)里,按Go语言的规则可以确信他已经在堆中了。

再分析一下代码,发现在给rule赋值的时候实际上是做了一次不必要的拷贝,后面用“&”取地址时候创建了一个逃逸的指针指向它的副本。

e6c1220a-6b35-11ed-8abf-dac502259ad0.png

最后解决办法也很容易想出,只需要把&移动到上面。

e6d2be98-6b35-11ed-8abf-dac502259ad0.png

这样就引用了切片中的结构体,避免了拷贝。

如何彻底避免?

在热议中,有网友分享了自己是怎么避免出现这个问题的。

对于每个结构体,把它看作纯值或纯指针,压根就不去使用&这种取地址的操作,避免隐式的内存分配。

e6f17946-6b35-11ed-8abf-dac502259ad0.png

如果你想要深入理解这个问题,也有人贴心的给出了需要提前了解的一些背景知识。

e705e700-6b35-11ed-8abf-dac502259ad0.png

最后有人指出,Rust语言为避免这个问题,直接规定必须显式操作才能拷贝一个数据结构。

e719c388-6b35-11ed-8abf-dac502259ad0.png

当你不习惯的时候这规定烦得要命,但是总的来看还是值得。

方便or规范,你更倾向于哪种做法?

审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4976

    浏览量

    74381
  • go语言
    +关注

    关注

    1

    文章

    159

    浏览量

    9848

原文标题:只改变一个字符使 Go 程序提速 42%

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    MIMXRT1189奇数长度UDP数据包的最后一个字节出现问题,为什么?如何解决?

    我遇到了问题,即奇数长度 UDP 数据包的最后一个字节无法通过线路正确发送。最后一个字节似乎是未初始化或过时的数据。如果我将 UDP 数据包填充到偶数长度(2 字节绑定),则数据始
    发表于 04-17 07:47

    求助 LabVIEW 字符串比较

    请教大神 ,用一个字符串和多个字符串比较程序应该怎么做。 比如:A字符串和B字符串组(B组字符
    发表于 03-02 17:24

    keil定义fputc函数

    中统调用。 // 设备文件写入一个字符 static int fputc_dev(int c,FILE * stream) { const libc_device_file *dev
    发表于 01-22 08:25

    单片机中的串口通讯串行同步通信与串行异步通信

    就保证了起始位开始处定会有下跳沿,由此就可以标志一个字符传输的起始。而根据起始位和停止位也就很容易的实现了字符的界定和同步。 显然
    发表于 01-15 08:06

    串口超时中断的原理与特点

    超时中断 (Timeout Interrupt - RTO, Receiver Timeout) 触发条件: 当最后次成功接收到一个字符后(RXNE 事件后),在预设的超时时间内没有接收
    发表于 11-17 07:42

    飞凌嵌入式ElfBoard-标准IO接口之格式化输入

    字符,格式说明符除外(%):任何不是空格字符(空白、换行符或制表符)或格式说明符(以%字符开头)的字符都会导致函数从流中读取下一个字符,将其
    发表于 11-12 08:35

    C语言的printf基本用法介绍

    十进制形式输出整数。除了 %d,printf 支持更多的格式控制,例如: %c:输出一个字符。c 是 character 的简写。 %s:输出一个字符串。s 是 string 的
    发表于 11-12 07:04

    原厂 FZH173是点阵式液晶显示驱动电路 LCD驱动

    驱动且需要低功耗的便携式产品。FZH173LCD驱动器由17公共信号驱动器和80段信号驱动器组成。最大显示RAM大小可以是1行中的80个字符,在双行显示中为40个字符。单个最多可以
    发表于 10-31 14:42

    RISC-V的工具链GCC内联汇编

    ;;\"作为分隔符,没有添加分隔符的两个字符串会被合并成为一个字符串。“汇编指令列表”的编写语法和普通的汇编程编写是样的。 4.\"输入操作数\",用来指定当前内联汇编程序的输入
    发表于 10-30 06:59

    E203串口中断使用总结

    () 开始重组数据。在这里,笔者假设通信不会丢包或者数据出错,因此不设置通信协议,规定了数据包的大小。main() 中的代码如下图: 当上位机用串口传数据时,会先从低位开始一个一个字符地传,因此在接受
    发表于 10-22 07:34

    电子加工企业必看!AI 视觉检测让马达保护器良率飙升,成本骤降!

    在电子加工行业,马达保护器是设备安全的 “守门人”—— 表面哪怕藏着毫米级脏污、少一个字符,都可能导致终端产品故障,轻则返工赔钱,重则丢客户、坏口碑。但现在,90% 的企业还在靠人工检测:质检员盯着
    的头像 发表于 10-16 14:23 412次阅读

    rt thread 按照官方视频一个字一个字敲都不行,连main函数都无法进入,为什么?

    编译工具链) 需求很简单,使led灯500ms闪烁。在不用rt thread的前提下是可以用到,目前为止例子都没跑出来,但是是对照官方视频敲都代码,官方不是也说了支持armgcc的吗? 看
    发表于 09-28 07:43

    文读懂:CWDM和DWDM的核心差异

    光纤通信里的“两兄弟”CWDM和DWDM,名字只差一个字母,差别可大了去!今天文讲透核心差异,小易帮你快速分清~
    的头像 发表于 09-17 18:19 1426次阅读
    <b class='flag-5'>一</b>文读懂:CWDM和DWDM的核心差异

    求助,关于STM32F030的iic主收问题求解

    我现在用stm32f030,在IIC的主模式下,想在收到一个字节数据后就回NACK和stop,但是现在实际情况是,我在接收到一个字节后进入接收中断再使能STOP,看波形是收到这个字节后
    发表于 06-24 07:54

    常用通信接口(串口、RS232、RS485、USB、TYPE-C原理与区别)

    、什么是串口通信?常见的串口通信般是指异步串行通信。与串行通信相对的是并行通信。数据传输般都是以字节传输的,一个字节8位。拿
    的头像 发表于 05-29 15:44 4467次阅读
    常用通信接口<b class='flag-5'>一</b>(串口、RS232、RS485、USB、TYPE-C原理与区别)