何时应该在Rust中使用inline?

132

Rust有一个"inline"属性,可以使用以下三种方式之一:

#[inline]

#[inline(always)]

#[inline(never)]

何时应该使用它们?

在Rust参考文献中,我们看到一个内联属性部分的说明:

编译器根据内部启发式方法自动内联函数。错误地内联函数实际上可能会使程序变慢,因此应谨慎使用。

在Rust内部论坛上,huon也保守地指定了内联

但是我们在 Rust 源码中看到了相当多的使用情况,包括标准库。许多一行函数都添加了内联属性,这应该很容易让编译器根据参考文献通过启发式方法进行优化。那么这些实际上是不需要的吗?

1个回答

102

当前Rust编译器的一个限制是,如果您没有使用LTO(链接时优化),它将不会在跨crate使用未标记#[inline]的函数中进行内联。 Rust使用类似于C ++的分离编译模型,因为LLVM的LTO实现在大型项目中无法扩展。因此,需要手动标记向其他crate公开的小函数。这不是一个很好的情况,未来可能通过改进LTO和MIR内联的某种组合来修复。

#[inline(never)]有时用于调试(分离预期不起作用的代码段)。理论上,它可以用于基准测试,但那通常是个坏主意:关闭内联不会阻止其他过程间优化,例如常量传播。对于常规代码而言,如果您有一个仅用于错误处理的常用辅助函数,则可以减少代码大小。

#[inline(always)]通常是个坏主意;如果一个函数够大以至于编译器默认不会将其内联,那么它足够大以至于调用的开销并不重要(过度内联增加指令缓存压力)。当然也有例外,但需要性能测量来证明其必要性。 这个例子是值得考虑的情况之一。 #[inline(always)]也可用于改善-O0代码质量,但通常不值得担心。


35
请注意,inline(never)用于panic内置函数上,以确保优化器不会将仅在panic情况下调用的函数进行内联。 - oli_obk
8
第一点评分为负一是因为缺少某些内容。通用项可以在跨板条箱时进行内联,因为它们在实例化时被有效地编译,所以用于内联的代码是随时可用的。这意味着许多未标记的这类项仍然可以在跨板条箱时进行内联。在某些基本库板条箱中,每个项都是通用的! - bluss
2
自从写作以来,跨板条箱(无LTO)的内联不足问题是否已经解决?如果没有,如果有类似#[inline] pub fn f() { g() }这样的东西,如果希望将g内联到另一个板条箱中的f的调用者中,是否也应该注释#[inline] - eggyal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接