我来自C,我想知道Rust的边界判断是否会影响性能.每次访问可能都需要一些额外的汇编指令,这在处理大量数据时可能会造成伤害.

另一方面,处理器性能中代价高昂的是内存,因此更多的算术汇编指令可能不会造成影响,但在加载缓存线后,顺序访问应该非常快,这可能很重要.

有人做过基准测试吗?

推荐答案

不幸的是,边界判断的成本并不容易估计.这当然不是"每次判断一个周期",也不是任何这样容易猜测的成本.它will有非零影响,但它可能无关紧要.

从理论上讲,通过修改Rust使其失效,并运行大规模的生态系统测试,可以衡量对基本类型(如Vec)进行边界判断的成本.这将给出某种经验法则,但如果不这样做,很难知道这是接近10%还是十分之一的开销.

不过,有一些方法比计时和猜测更好.这些经验法则主要适用于桌面级硬件;低端硬件或针对不同细分市场的产品将具有不同的特点.

If your indices are derived from the container size,编译器might很有可能完全消除边界判断.在这一点上,在发布版本中进行边界判断的唯一代价是它会间歇性地干扰优化,而优化通常不会妨碍其他优化.

If your code is branchy, memory access heavy or otherwise hard to optimise, and the bounds to check are easy to access,边界判断很有可能主要在CPU的空闲带宽中进行,分支预测特别有帮助,在这种情况下,总体成本将特别小,尤其是与其余代码的成本相比.

If your bounds to check are behind several layers of pointers,这是plausible,你会遇到内存延迟的问题,并会相应地受到影响.然而,CPU中的推测和预测机制将设法掩盖这一点也是合理的;这是非常依赖上下文的.如果您正在引用其中的数据,而不是在边界判断的同时取消对它的引用,那么这种风险会放大.

If your bounds checks are in a tight arithmetic loop that doesn't saturate the core,除非妨碍其他编译器优化,否则不太可能直接影响吞吐量.然而,阻碍其他编译器优化可能是非常糟糕的,从没有区别到阻止SIMD并导致10倍的减速.

If your bounds checks are in a tight arithmetic loop that does saturate the core,如果你承担了上述风险and,每次边界判断的直接执行惩罚大约为半个周期.

If your code is large enough to stress the instruction cache,那么您需要担心对代码大小的影响.这通常是适度的,但很难衡量的运行时影响.

彼得·科尔德斯在 comments 中补充了一些进一步的观点.首先,边界判断意味着加载和存储,所以您将运行混合加载,这很可能会在问题/重命名时出现瓶颈.第二,即使并行执行的预测分支也会从预测器中获取资源,这可能会导致其他分支的预测更糟.

这可能看起来很吓人,事实的确如此.这就是为什么在与您和您的代码相关的级别上衡量和理解您的性能是很重要的.

同样的情况是,自从Rust与边界判断"诞生"以来,它已经产生了降低其成本的方法,比如无处不在的零成本引用、迭代器(它吸收边界判断,但实际上并不移除边界判断),以及一组不同寻常的好用函数.如果你发现自己碰到了一个病态病例, rust 迹也会提供不安全的逃生舱口.

Rust相关问答推荐

为什么我们不能通过指针算法将Rust原始指针指向任意地址?'

在rust中如何修改一个盒装函数并将其赋回?

为什么我可以跟踪以前borrow 过的变量?房主在哪里?

在使用#[NO_STD]时,如何在Rust中收到紧急消息?

为什么这是&q;,而让&q;循环是无限循环?

如何点击()迭代器?

如何在递归数据 struct 中移动所有权时变异引用?

不能在一个代码分支中具有不变的自身borrow ,而在另一个代码分支中具有可变的self borrow

Rust编译器似乎被结果类型与anyhow混淆

为什么 `Deref` 没有在 `Cell` 上实现?

实现 Deref 的 struct 可以返回对外部数据的引用吗?

如何在 Rust 中将函数项变成函数指针

Sized问题的动态调度迭代器Rust

注释闭包参数强调使用高阶排定特征界限

str 和 String 的 Rust 生命周期

Rust:`sort_by` 多个条件,冗长的模式匹配

内部值发生变化时 Rc 的行为

类型判断模式匹配panic

为什么我可以从读取的可变自引用中移出?

BigUint 二进制补码