剖析使Go语言高效的5个特性(2/5): 函数调用不是免费的

翻译原文链接 转帖/转载请注明出处

英文原文链接 发表于2014/06/07

函数调用不是免费的

一个函数调用有三个步骤。创建一个新的堆栈框(stack frame)并把调用者的详细信息记录下来。把任何会被被调用函数用到的寄存器内容保存到堆栈。计算被调用函数的地址,并执行跳转指令到那个新的地址。

因为函数调用是频繁操作,CPU的设计者花费了很多精力来优化这个过程,但他们不可能消除所有的开销。

根据被调用函数的功能,这个调用开销可能是可以忽略不计的,也可能是非常显著的。有一个降低调用开销的优化技术叫内联(inlining)

Go语言编译器通过把被调用函数代码当作调用者代码的一部分来实现内联。内联也是有代价的。它会增加编译出来的二进制可执行文件的大小。只有在调用函数的开销占到被调用函数本身的工作量很大一部分的时候,内联才有意义。所以只有简单的函数才被考虑启用内联。调用函数的开销往往不占复杂函数的大头,所以他们也就不会被内联。

上面这个例子展示了函数Double对util.Max的调用。为了降低调用util.Max的成本,编译器会把util.Max内联到Double函数里,产生如下内容:

内联之后,util.Max将不会被调用,但是Double的行为并没有改变。内联并不是Go语言独有的。几乎所有编译的或者即时编译(JITed)的语言会提供这项优化。那么Go语言里的内联是怎么工作的呢?

Go语言的实现非常简单。当一个包(package)被编译的时候,任何适合内联的小函数都被标记并且按正常情况编译。然后将源代码和编译后的二进制同时保存下来。

上面的图片显示了util.a的内容。源代码被做了稍微的改动以方便编译器的快速处理。当编译器编译Double的时候,它会发现util.Max是可以内联的并且util.Max的源代码也存在。这时编译器会插入原函数的源代码,而不是插入一个util.Max的调用。

保存源代码还使得其它优化成为可能。

比如上面这个例子,虽然Test函数总是返回false,Expensive在执行它之前是无法知道的。但是当Test被内联的时候,我们就得到了如下的代码:

这样编译器就能知道那块代码是不会被执行到的。

这样不仅节省了调用Test函数的开销,它还节省了编译任何不会被执行的代码。Go编译器能够自动在多个文件或者包(package)之间实现函数内联。如果某些代码调用了来自标准库的可内联函数,Go编译器同样可以将这些函数内联进来。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


类型转换 1、int转string 2、string转int 3、string转float 4、用户结构类型转换
package main import s "strings" import "fmt" var p = fmt.Println func main() { p("Contains: ", s.Contains("test&quo
类使用:实现一个people中有一个sayhi的方法调用功能,代码如下: 接口使用:实现上面功能,代码如下:
html代码: beego代码:
1、读取文件信息: 2、读取文件夹下的所有文件: 3、写入文件信息 4、删除文件,成功返回true,失败返回false
配置环境:Windows7+推荐IDE:LiteIDEGO下载地址:http://www.golangtc.com/downloadBeego开发文档地址:http://beego.me/docs/intro/ 安装步骤: 一、GO环境安装 二、配置系统变量 三、Beego安装 一、GO环境安装 根
golang获取程序运行路径:
Golang的文档和社区资源:为什么它可以帮助开发人员快速上手?
Golang:AI 开发者的实用工具
Golang的标准库:为什么它可以大幅度提高开发效率?
Golang的部署和运维:如何将应用程序部署到生产环境中?
高性能AI开发:Golang的优势所在
本篇文章和大家了解一下go语言开发优雅得关闭协程的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。1.简介本文将介绍首先为什么需要主...
这篇文章主要介绍了Go关闭goroutine协程的方法,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。1.简介本文将介绍首先为什么需要主动关闭gor...
本篇文章和大家了解一下go关闭GracefulShutdown服务的几种方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。目录Shutdown方法Regi...
这篇文章主要介绍了Go语言如何实现LRU算法的核心思想和实现过程,具有一定借鉴价值,需要的朋友可以参考下。下面就和我一起来看看吧。GO实现Redis的LRU例子常
今天小编给大家分享的是Go简单实现多租户数据库隔离的方法,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会...
这篇“Linux系统中怎么安装NSQ的Go语言客户端”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希
本文小编为大家详细介绍“怎么在Go语言中实现锁机制”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么在Go语言中实现锁机制”文章能帮助大家解决疑惑,下面...
今天小编给大家分享一下Go语言中interface类型怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考