什么时候应该在 Rust 中使用内联?

When should inline be used in Rust?

Rust 有一个 "inline" 属性,可用于这三种风格之一:

#[inline]

#[inline(always)]

#[inline(never)]

什么时候使用它们?

在 Rust 参考中,我们看到 an inline attributes section

The compiler automatically inlines functions based on internal heuristics. Incorrectly inlining functions can actually make the program slower, so it should be used with care.

在 Rust 内部论坛中,huon 也是 conservative about specifying inline

但我们在 Rust 源代码中看到 considerable usage,包括标准库。单行函数中添加了很多内联属性,编译器应该很容易根据参考资料通过启发式方法发现和优化。那些实际上不需要吗?

当前 Rust 编译器的一个限制是,如果您不使用 LTO(Link-时间优化),它永远不会跨板条箱内联未标记 #[inline] 的函数。 Rust 使用类似于 C++ 的单独编译模型,因为 LLVM 的 LTO 实现不能很好地扩展到大型项目。因此,暴露给其他 crate 的小函数需要手工标记。这不是一个很好的情况,将来可能会通过对 LTO 和 MIR 内联的一些改进组合来解决。

#[inline(never)] 有时对调试很有用(分离一段没有按预期工作的代码)。从理论上讲,它可以用于基准测试,但这通常是个坏主意:关闭内联不会阻止其他过程间优化,如常量传播。就普通代码而言,如果你有一个经常使用的辅助函数,它只用于错误处理,它可以减少代码大小。

#[inline(always)] 通常是个坏主意;如果一个函数足够大以至于编译器默认不会内联它,那么它就足够大以至于调用的开销无关紧要(过多的内联会增加指令缓存压力)。有例外,但您需要性能测量来证明它的合理性。 This example 是一种值得考虑的情况。 #[inline(always)] 也可用于提高 -O0 代码质量,但这通常不值得担心。