内联 (Inlining) :
- 内联是一种优化技术,它通过将函数的代码直接插入到调用它的地方来减少函数调用的开销。这通常可以提高程序的执行速度,但也可能会增加程序的大小,因为相同的代码可能会在多个地方复制
- 内联主要通过减少函数调用的开销来优化代码的执行速度。这通常在函数体非常小,调用非常频繁时最为有效。通过使用
#[inline]
属性,你可以向编译器提示一个函数可能是一个内联的好候选者。下面是一些具体的例子和解释:
基本的内联 :
rust
```
rustCopy code
#[inline]
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let sum = add(5, 7);
println!("{}", sum); // Output: 12
}
```
在这个例子中,add
函数前面有一个#[inline]
属性,提示编译器应该尽量将这个函数内联。如果编译器接受这个提示,它会将add
函数的代码直接插入到调用它的地方,从而减少函数调用的开销。
总是内联 :
rust
```
rustCopy code
#[inline(always)]
fn always_inline(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let sum = always_inline(5, 7);
println!("{}", sum); // Output: 12
}
```
在这个例子中,always_inline
函数前面有一个#[inline(always)]
属性,它告诉编译器应该总是将这个函数内联,不管它的大小或复杂度。
rust
### 从不内联 :
```
rustCopy code
#[inline(never)]
fn never_inline(a: i32, b: i32) -> i32 {
a + b
}
fn main() {
let sum = never_inline(5, 7);
println!("{}", sum); // Output: 12
}
```
在这个例子中,never_inline
函数前面有一个#[inline(never)]
属性,它告诉编译器应该从不将这个函数内联。这可能在你不希望某个函数内联,或者想保持函数调用的清晰性时有用。
优劣势:
内联可以减少函数调用的开销,可能会提高程序的运行速度,但也可能会增加代码的大小。过度的内联可能会导致代码膨胀,从而降低缓存的效率。所以,应该谨慎地使用内联,确保它能提高程序的性能而不是降低性能。
默认情况
在 Rust 中,默认情况下,编译器会根据一些因素来决定是否将函数内联,例如优化级别和函数的大小。具体来说,非泛型函数在跨crate的情况下不会被内联,除非使用了链接时优化(Link-Time Optimization,LTO);而泛型函数可能会被内联。这种默认的内联行为可以在一些简单的情况下提供好的效果,例如非常小的函数或只在一个地方被调用的函数,编译器通常会自行决定将这些函数内联,即使没有 #[inline]
属性
在 Rust 中,一个编译单元是一个 crate,如果函数 f
在 crate A 中定义,那么所有从 A 中对 f
的调用都可以被内联,因为编译器可以完全访问 f
。但是,如果 f
从某个下游的 crate B 被调用,这些调用就不能被内联,因为 B 只能访问 f
的签名,而不能访问其主体
如果想要制作编译器可以制作的最快的二进制文件,可以/应该使用链接时优化(rustc -C lto
),它可以访问 crate 的所有 Rust 依赖项,并且可以内联,包括没有 #[inline]
属性的函数。如果函数是泛型函数(例如,如果在 fn 或 surrounding impl 上有一个或多个类型参数 - 生命周期参数不算),则可以在没有 #[inline]
提示的情况下跨 crate 进行内联 通过使用#[inline]
、#[inline(always)]
和#[inline(never)]
等属性,开发人员可以为编译器提供内联函数的指南,从而有可能提高程序的性能。