刺激代码内联

时间:2016-12-13 11:15:46

标签: go inline

与C ++这样的语言不同,你可以在其中明确地陈述inline,在Go中,编译器动态地检测内联的候选函数(C ++也可以这样做,但Go不能同时执行这两种操作)。还有一个调试选项可以看到可能的内联发生,但是很少有人在线记录go编译器执行此操作的确切逻辑。

假设我需要每n个周期重新运行一组数据的大循环;

func Encrypt(password []byte) ([]byte, error) {
    return bcrypt.GenerateFromPassword(password, 13)
}

for id, data := range someDataSet {
    newPassword, _ := Encrypt([]byte("generatedSomething"))
    data["password"] = newPassword
    someSaveCall(id, data)
}

Encrypt为例,正确地内联编译器需要考虑哪些逻辑?

我从C ++中知道,通过引用传递将增加自动内联的可能性而不使用显式inline关键字,但是要理解编译器确定选择内联与否的决策的确切方法并不容易走。例如PHP这样的脚本语言会受到极大的影响,如果你使用常量addSomething($a, $b)进行循环,其中基准测试如此十亿次的成本与$a + $b(内联)相比几乎是荒谬的。

2 个答案:

答案 0 :(得分:7)

Quoting minux(2013-01-31):

  

默认情况下,内联器将尝试内联叶函数(不调用其他函数/方法/接口),不会调用恐慌或恢复或选择或切换或创建闭包或转/延函数(参见下面的示例)并且在表示时少于40个节点(大致对应于40个简单操作)。但请注意,这只描述了gc编译器的当前现状,并且将来肯定会有所改进。因此,请尽量不依赖于此。

在遇到性能问题之前,你不应该关心。内联与否,它也会这样做。

如果表现确实重要并且它具有明显的显着差异,那么就不要依赖当前(或过去)的内联条件,"内联"它自己(不要把它放在一个单独的功能)。

可以在$GOROOT/src/cmd/compile/internal/gc/inl.go文件中找到规则。您可以使用'l'调试标志来控制其侵略性。

// The inlining facility makes 2 passes: first caninl determines which
// functions are suitable for inlining, and for those that are it
// saves a copy of the body. Then inlcalls walks each function body to
// expand calls to inlinable functions.
//
// The debug['l'] flag controls the aggressiveness. Note that main() swaps level 0 and 1,
// making 1 the default and -l disable.  -ll and more is useful to flush out bugs.
// These additional levels (beyond -l) may be buggy and are not supported.
//      0: disabled
//      1: 40-nodes leaf functions, oneliners, lazy typechecking (default)
//      2: early typechecking of all imported bodies
//      3: allow variadic functions
//      4: allow non-leaf functions , (breaks runtime.Caller)
//
//  At some point this may get another default and become switch-offable with -N.
//
//  The debug['m'] flag enables diagnostic output.  a single -m is useful for verifying
//  which calls get inlined or not, more is for debugging, and may go away at any point.

另请查看博客帖子:Dave Cheney - Five things that make Go fast(2014-06-07),其中写有关于内联的内容(长篇文章,它在中间,搜索"内联"字)。

关于内联改进的有趣讨论(也许是Go 1.9?):cmd/compile: improve inlining cost model #17566

答案 1 :(得分:1)

更好的是,不要猜测,衡量! 您应该信任编译器并避免尝试猜测其内部工作原理,因为它将从一个版本更改为下一个版本。 编译器,CPU或缓存可以起到很多技巧,能够从源代码中预测性能。

如果内联使你的代码更大到不再适合缓存行,那么它会比非内联版本慢得多吗?缓存局部性对性能的影响要大于分支。