专栏首页艺述思维有人说 Go 语言性能不行,大佬不服,使用 pprof 三步优化代码,性能堪比 C++

有人说 Go 语言性能不行,大佬不服,使用 pprof 三步优化代码,性能堪比 C++

这篇文章部分转自:https://www.cnblogs.com/qcrao-2018/p/11832732.html

目录

1,CPU 优化

2,内存优化

3,GC 优化

4,小结


这篇文章讲了一个故事,大意是 Go 语言大佬 Russ Cox 发现一篇文章说使用 Go 写的算法很慢,而 C++ 很快。大佬哪受得了这个,于是使用 Go 语言性能优化神器 pprof,开始了优化实战。最终经过三轮优化,基本上能达到和 C++ 同等的速度和同样的内存消耗。这三轮优化十分具有借签与学习之意义,简述如下:

1,CPU 优化

首先,使用如下代码开启 CPU 监测:

pprof.StartCPUProfile(f)

耗时 top5 的函数,发现一个读 map 的函数耗时最长:mapaccess1_fast64,而它出现在一个递归函数中。执行 web mapaccess1 命令,聚焦出调用 mapaccess1_fast64 函数最多的就是 main.FindLoops 和 main.DFS,再执行命令:list DFS,定位到相关的具体代码。

优化的方法是将 map 改成 slice。当然并不是所有的map都需要这样做,在这个案例中能这样做,和 key 的类型是 int 而且不是太稀疏有关。具体问题需要具体分析,这正是 pprof 工具的价值所在。

修改完之后,再次通过 cpu profiling,发现递归函数 mapaccess1_fast64 的耗时已经不在 top5 中了,但是新增了长耗时函数:runtime.mallocgc,占比 54.2%,而这和内存分配以及垃圾回收相关。

2,内存优化

使用如下代码开启内存监测:

FindHavlakLoops(cfgraph, lsgraph)
f,_ := os.Create(*memprofile)
pprof.WriteHeapProfile(f)

继续通过 top5、list 命令找到内存分配最多的代码位置,发现这回是向 map 里插入元素使用的内存比较多。

改进方式同样是用 slice 代替 map。但 map 有一个缺点,就是可以重复插入元素,因此写一个向 slice 插入元素的函数,可以防止重复插入:

func appendUnique(a []int, x int) []int {
    for _, y := range a {
        if x == y {
            return a
        }
    }
    return append(a, x)
}

好了,现在程序比最初的时候快了 2.1 倍。再次查看 cpu profile 数据,发现 runtime.mallocgc 降了一些,但仍然占比 50.9%。因此需要查看垃圾回收到底在回收哪些内容,这些内容就是导致频繁垃圾回收的“罪魁祸首”。

3,GC 优化

使用 web mallocgc 命令,将和 mallocgc 相关的函数用矢量图的方式展现出来,但是有太多样本量很少的节点影响观察,增加过滤命令:

go tool pprof --nodefraction=0.1 profile

在这条指令中,将少于 10% 的采样点过滤掉。

(注:这是 pprof 生成的分析结果)

新的矢量图可以直观地看出,FindLoops 触发了最多的垃圾回收操作。继续使用命令 list FindLoops 直接找到代码的位置。原来,每次执行 FindLoops 函数时,都要 make 一些临时变量,这会加重垃圾回收器的负担。

改进方式是增加一个全局变量 cache,这样可以重复利用。虽然这样做的坏处是,线程不是安全的了。

4,小结

使用 pprof 工具进行的优化到这就结束了。最后值得提一下,大佬做这件事的时间比较久远,最初写于 2011 年,原文在这里:

https://blog.golang.org/profiling-go-programs

(Russ Cox 优化过程,并附上代码)

原文有更多内容和参考资料,如果有时间推荐查看。

pprof 的包路径是 "runtime/pprof",可以通用报告生成、Web 可视化界面、交互式终端 三种方式来使用。具体使用方法可查相关文档。

本文分享自微信公众号 - 艺述思维(yishulun2005)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 什么是Java中的魔法值?

    魔法数值、魔法数字、魔法值,这是一个东西,不同的叫法。 所谓魔法值,是指在代码中直接出现的数值,只有在这个数值记述的那部分代码中才能明确了解其含义。

    一觉睡到小时候
  • 说说提高Python运行效率的技巧?

    答:不喜欢Python的人经常会吐嘈Python运行太慢。今天具体来说一下提高python执行效率的方法,下面给大家介绍10种方法 。

    用户1564362
  • HLS中的位操作可以这么做

    标准C++中已经提供了位运算符,包括位求反、左移、右移、位与、位异或以及位或。在此基础上,HLS考虑到硬件的一个特性,那就是获取数据中的某一位或者某几位,同时,...

    Lauren的FPGA
  • 牛逼了!这个私藏的 IDE 插件,撸码 6 的飞起,编程效率提高 30 倍!

    平时写代码的时候多少会依赖编辑器里面的代码补全,敲几个字母就能补全一整个词。可是这么多年过去了,为什么代码补全还是像最开始那样,只能限定于一个词,而且毫无意义地...

    用户6543014
  • 图解Vivado HLS设计流程

    在ESL(ElectronicSystem Level)阶段,典型的特征之一就是采用高层次语言完成设计。这里的“高层次”是相对于传统的RTL语言(VHDL/Ve...

    Lauren的FPGA
  • 这个世界本就是残酷的,所以你不能怪C++向你展示了世界的本质

    很多已经做了几年的C++程序员已经很自信觉得这门编程语言算是熟悉阶段了,但是当重新对这门语言来个彻底大扫除的时候发现,又有新的语法出现,最糟糕的是之前掌握的很多...

    诸葛青云
  • 【Rust日报】 2019-10-29 async-std v0.99.11 发布

    支持 2D 以及 3D 的流体模拟。提供多种类型的流体模拟,并且可以和 nphysics 引擎配合使用。了解更多

    MikeLoveRust
  • 使用 Hugo 搭建私人博客

    第一次博客建设是使用的 Emacs 的 Org mode 导出的 html 和自带的生成网页链接的方式生成博客,但是当数量超过 20 之后,每次生成的时间都会显...

    zucchiniy
  • 关于PR必须知道的几个基本术语

    自底向上综合方式。在Vivado下,这种综合方式其实就是指OOC(Out-of-context)综合方式。采用该综合方式,Vivado会对相应的模块生成独立的网...

    Lauren的FPGA
  • css3的一些属性--position

    wust小吴

扫码关注云+社区

领取腾讯云代金券