c - 将性能关键循环从 C 翻译成 Rust

标签 c rust translate

我正在尝试将一些旧的 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;  
    }
}

您如何以高效的方式将其转化为 Rust?我的问题是,虽然我可能可以获得我想要的功能,但我不确定如何才能获得(大致)相同的速度。

这部分代码是我们代码(至少这部分代码)的主要瓶颈,在翻译时希望保留以下属性。

  1. 循环应该尽快中断,因为 asize 可能非常大。
  2. firstEdgefirstEdgeRight 大致同时被发现。因此,只有一个循环而不是两个循环是一件好事 - 为了避免再次从头开始搜索(即使我认为这个解决方案会杀死预取器(但我不确定,也许是运行代码的旧机器甚至没有预取器))。

虽然性能很重要,但可读性当然更重要:)

编辑 好的,这是我可能的 Rust 实现(cond_right()cond_left() 被排除在外)。 我考虑的事情是:

  1. 如果其他人必须从头开始实现,他们会这样写吗?
  2. 我真的需要让 first_edgefirst_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;
    }
}

最佳答案

你需要做好选择的准备:

  1. How would you translate that into Rust in a performant way?

  2. while performance is important, readability is of course even more important

哪个对你来说更重要?以下是我将如何编写代码,假设我已经理解您的要求:

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);
}

我们从左到右迭代一次,从右到左迭代一次。我的直觉告诉我,这将为代码提供简单的分支预测,以线性方式访问内存,两者都应该是可优化的。

但是,变量名 asize 让我停顿了一下。它听起来确实像是“数组大小”的缩写。如果是这样的话,那么我会 100% 推荐使用切片而不是数组索引。为什么?因为数组访问 (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));

但是,您的问题只有一个可能的正确答案:

使用分析器

使用分析器

使用分析器

使用分析器

只有知道您的实际数据、您对条件的实际实现、您正在运行的其余代码等,您才能真正知道某件事的速度有多快。

Therefore it has been a good thing to only have one loop instead of two - in order to avoid search from the beginning again

这对我来说是不直观的,所以我希望看到支持声明的分析结果。

关于c - 将性能关键循环从 C 翻译成 Rust,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34762541/

相关文章:

c - 将 C 语言翻译成 ARM 汇编语言

python - 对 python-dev header 中函数的 undefined reference

C:交换二维数组中值的函数

c - C 中修改后的 N 皇后区

rust - 添加两个数字而不克隆两者

types - 为什么 Rust 不能推断 Iterator::sum 的结果类型?

c++ - 不同数组声明的类型

rust - 在 and_then 的类型定义中, T 从哪里来?

cocoa - 如何平移和缩放 NSImage?

java - 如何将 SQL 写入 JPQL