我正在尝试将一些旧的C代码重写为Rust - 我是新手.我遇到的一个反复出现的问题是C代码有很多这样的循环:
for (i = startIndex; i < asize; i++)
{
if (firstEdge < 0 && condLeft(i))
{
firstEdge = i;
}
RightIndex = asize-1-i;
if (firstEdgeRight < 0 && condRight(RightIndex))
{
firstEdgeRight = RightIndex;
}
// Found both edges
if (firstEdge >= 0 && firstEdgeRight >= 0) {
break;
}
}
Run Code Online (Sandbox Code Playgroud)
你会如何以高效的方式将其转化为Rust?我的问题是,虽然我可能得到我想要的功能,但我不确定如何获得(大致)相同的速度.
这部分代码是我们代码中的主要瓶颈(至少这部分代码),并且在翻译时它希望保留以下属性.
asize它可能非常大.firstEdge并firstEdgeRight在同一时间大致找到.因此,只有一个循环而不是两个循环是一件好事 - 为了避免再次从头开始搜索(即使我认为这个解决方案会杀死预取器(但我不确定,也许旧机器运行代码)甚至没有预取器)).虽然性能很重要,但可读性当然更为重要:)
编辑好的,这是我可能实现的Rust(cond_right()并且cond_left()被遗漏了).我想到的是:
first_edge和first_edge_right变异吗?它们在我的实现中,但我感觉不对,因为它们只被分配一次.let mut first_edge = -1;
let mut first_edge_right = -1;
// Find first edge
let start_index = 300; // or something
let asize = 10000000;
for i in start_index..asize {
if first_edge < 0 && cond_left(i) {
first_edge = i;
}
let right_index = asize - i -1;
if first_edge_right < 0 && cond_right(right_index) {
first_edge_right = right_index;
}
if (first_edge >= 0 && first_edge_right >= 0) {
break;
}
}
Run Code Online (Sandbox Code Playgroud)
你需要做好选择的准备:
你会如何以高效的方式将其转化为Rust?
虽然性能很重要,但可读性当然更为重要
哪个对你来说更重要?这是我编写代码的方式,假设我已经理解了你的要求:
fn left_condition(i: usize) -> bool {
i > 1000
}
fn right_condition(i: usize) -> bool {
i % 73 == 0
}
fn main() {
let start_index = 300;
let asize = 10000000;
let left = (start_index..asize).position(left_condition);
let right = (start_index..asize).rev().position(right_condition);
println!("{:?}, {:?}", left, right);
}
Run Code Online (Sandbox Code Playgroud)
我们从左到右迭代一次,从右到左迭代一次.我的直觉告诉我,这将为代码提供简单的分支预测,以线性方式访问内存,这两者都应该是可优化的.
但是,变量名称asize让我暂停.它当然听起来像"数组大小"的缩写.如果是这种情况,那么我会100%建议使用切片而不是数组索引.为什么?因为数组access(foo[0])通常有边界检查的开销.我会用切片写一些东西:
let data = vec![0; 10_000_000];
let start_index = 300;
let slice = &data[start_index..];
let left = slice.iter().position(|&i| left_condition(i));
let right = slice.iter().rev().position(|&i| right_condition(i));
Run Code Online (Sandbox Code Playgroud)
但是,对于您的问题,只有一个可能的真实答案:
使用分析器
只知道您的实际数据,条件的实际实现,您正在运行的其余代码等,您才能真正了解某些事情的速度.
因此,只有一个循环而不是两个循环是一件好事 - 为了避免再次从头开始搜索
这对我来说不直观,所以我希望看到支持声明的分析结果.