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

    文章

    4780

    浏览量

    68539
  • go语言
    +关注

    关注

    1

    文章

    158

    浏览量

    9047

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

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

收藏 人收藏

    评论

    相关推荐

    stm32/gd32 wifi模块通信异常问题

    的,wifi模块都回复一个字符,这个字符还是发送指令中的任意(发送\"AT\",回\"A\"或\"T\"),有时候干脆回复\"erro
    发表于 10-21 08:59

    鸿蒙原生应用元服务开发-仓颉基础数据类型字符类型

    对单引号或双引号包含的字符。 单个字符字符字面量举例: let a: Rune = r\'a\' let b: Rune = r\"b\" 转义
    发表于 09-19 10:58

    MATLAB(5)--字符串处理

    字符串表示 在MATLAB中,字符串是用单引号括起来的字符序列,是把一个字符串当做一个行向量,这个行向量中,每个元素对应
    发表于 09-06 10:22

    vim的操作方式有哪几种

    模式下,用户可以执行各种命令来操作文本,例如移动光标、删除文本、复制文本等。以下是命令模式下的些常用操作: 1.1 光标移动 在命令模式下,用户可以使用以下按键来移动光标: h:向左移动一个字符 j:向下移动一个字符 k:向上
    的头像 发表于 08-30 14:54 559次阅读

    vim的三种工作模式有哪些

    自动进入普通模式。在普通模式下,你可以使用各种快捷键来移动光标、复制、粘贴、删除和查找文本等。 1.1 光标移动 在普通模式下,你可以使用以下快捷键来移动光标: h:向左移动一个字符 j:向下移动一个字符 k:向上移动一个字符
    的头像 发表于 08-30 14:52 749次阅读

    请问AT命令可以支持多少个字符

    AT命令可以有多长?当输入命令长度超过 128 个字符时,它看起来 AT 自定义命令会中断。
    发表于 07-16 06:17

    使用CIPDOMAIN命令时,解析长度为64个字符或更大的DNS名称失败了,为什么?

    s3.dualstack.us-east-1.amazonaws.com 的CNAME记录。 我转储了 libat.a 存档并找到了at_setupcipomain函数,似乎分配要在堆栈上复制的 64 字节的字符串。 首先,有人可以确认这个限制吗? 其次,我们能否获
    发表于 07-11 07:59

    FX3在安卓系统上显示为\"DDC\",有什么办法可以定义这个字符串吗?

    正如标题所说,当我将 FX3 插入安卓设备时,安卓会询问应用程序是否可以访问\"DDC\" 。 有什么办法可以定义这个字符串吗? 谢谢!
    发表于 07-03 08:15

    JDY-08蓝牙模块AT指令响应只能接收到第一个字符是怎么回事?

    STM8L051的RX线上有完整的对应+OK的字符的波形。且波特率在误差范围内。 4、试了其他板子,也换了其他波特率和改变停止位、校验位,都还是只能接收第一个字符。 5、程式上,在接收中断里都是简单的赋值
    发表于 05-07 07:50

    如何提取串口接收字符串数组里的某个字符串?

    条(有时候二十多条不定)响应字符串指令,我是用一个字符串数组来接收这些返回来的指令的。我现在只需要读取数组里的某条指令,应该怎么把它提取出来啊??有哪位前辈懂的,希望能提供点帮助。我找了好久找到
    发表于 04-22 06:05

    深入解析西门子博途文本块接口的结构与功能

    STRING 和 WSTRING 数据类型存储一个字符串中的多个字符。允许在字符串中使用任何 ASCII码类型的字符。这些字符将使用
    发表于 04-11 11:23 1210次阅读
    深入解析西门子博途文本块接口的结构与功能

    使用i2c从从站读取两个字节时,为什么主站发送一个字节后就发送NACK呢?

    当我使用 i2c 从从站读取两个字节时,有时会返回 RX_OVERFLOW。 我使用逻辑分析仪抓取总线波形,发现接收到一个字节,主控器发出 NACK,之后返回错误代码
    发表于 03-05 07:42

    请问XMC4500串口接收一个字节产生中断会有问题吗?

    用XMC4500的开发板做串口中断,在每次接收单个字符时,我单步运行,查看PSR寄存器。接收中断对数据有两种响应。1。当数据字节最高位不为1,剩余7位中1的个数为偶数时,PSR的第14位(RIF)置
    发表于 02-06 06:35

    spi读取多个字节的时候该怎么判断UART的上一个字节已经读完了?

    想问下 spi 的 SPI_SpiIsBusBusy() 的这个API在 UART 中怎么实现,读取多个字节的时候该怎么判断 UART 的上一个字节已经读完了?
    发表于 02-02 06:54

    如何解决Python爬虫中文乱码问题?Python爬虫中文乱码的解决方法

    决Python爬虫中文乱码问题。 、了解字符编码 在解决乱码问题之前,我们首先需要了解些基本的字符编码知识。常见的字符编码有ASCII、
    的头像 发表于 01-12 15:11 2350次阅读