【转】Go语言inline内联的策略与限制
感觉像是 编译器优化 方面的一些知识。
angular 打包出来的,其实也是类似编译之后的。
原文: https://pengrl.com/p/20028/
--------------------------------------------------
本文基于Go 1.13
。
内联,就是将一个函数调用原地展开,替换成这个函数的实现。尽管这样做会增加编译后二进制文件的大小,但是它可以提高程序的性能。那么Go语言中,什么样的函数可以被内联呢?我们一起来看。
规则
让我们从一个示例开始。下面这个程序的源码,分别编写在两个文件中,作用是对一组数字进行加或减:
1
|
main.go
|
使用参数-gflags="-m"
运行,可显示被内联的函数:
1
|
./op.go:3:6: can inline add
|
可以看到add方法被内联了。但是,为什么sum方法没有被内联呢?使用运行参数-gflags="-m -m"
可以看到原因:
1
|
./main.go:10:6: cannot inline sum: unhandled op RANGE
|
Go不会内联包含循环的方法。实际上,包含以下内容的方法都不会被内联:闭包调用,select,for,defer,go关键字创建的协程。并且除了这些,还有其它的限制。当解析AST时,Go申请了80个节点作为内联的预算。每个节点都会消耗一个预算。比如,a = a + 1
这行代码包含了5个节点:AS, NAME, ADD, NAME, LITERAL。以下是对应的SSA dump:
当一个函数的开销超过了这个预算,就无法内联。以下是一个更复杂的add函数对应的输出:
1
|
/op.go:3:6: cannot inline add: function too complex: cost 104 exceeds budget 80
|
当一个函数满足上面的所有条件,它就可以被内联。然而,依据以往的开发经验,内联优化可能带来一些其他问题。
挑战
举个例子,当发生panic时,开发者需要知道panic的准确堆栈信息,获取源码文件以及行号。那么问题来了,被内联的函数是否还有正确的堆栈信息呢?以下是一个包含了panic的内联方法:
1
|
func add(a, b float32) float32 {
|
运行这个程序,我们可以看到panic显示了正确的源码行号,尽管它被内联了:
1
|
panic: Do not add negative number
|
这是因为,Go在内部维持了一份内联函数的映射关系。首先它会生成一个内联树,我们可以通过-gcflags="-d pctab=pctoinline"
参数查看。以下是用sum方法的汇编代码构建出的内联树:
Go在生成的代码中映射了内联函数。并且,也映射了行号,可以通过-d pctab=pctoline
参数查看。以下是sum方法的输出:
源码文件,可以通过-gcflags="-d pctab=pctofile"
查看:
现在,我们得到了一张映射表:
这张表被嵌入到了二进制文件中,所以在运行时可以得到准确的堆栈信息。
内联带来的性能提升
内联是高性能编程的一种重要手段。每个函数调用都有开销:创建栈帧,读写寄存器,这些开销可以通过内联避免。但话说回来,对函数体进行拷贝也会增大二进制文件的大小。以下是内联与非内联时的一个benchmark对比:
1
|
name old time/op new time/op delta
|
内联的性能大概要好5~6%左右。
英文地址: https://medium.com/a-journey-with-go/go-inlining-strategy-limitation-6b6d7fc3b1be
本文完,作者yoko,尊重劳动人民成果,转载请注明原文出处: https://pengrl.com/p/20028/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2018-05-17 【转】Linux 中清空或删除大文件内容的五种方法(truncate 命令清空文件)