如何在Rust中提高元素乘法的性能?

ryn*_*n1x 6 optimization performance rust

我将使用10 ^ 6 +元素对多个向量进行元素乘法.这在标题中被标记为我的代码中最慢的部分之一,所以我该如何改进它?

/// element-wise multiplication for vecs
pub fn vec_mul<T>(v1: &Vec<T>, v2: &Vec<T>) -> Vec<T>
where
    T: std::ops::Mul<Output = T> + Copy,
{
    if v1.len() != v2.len() {
        panic!("Cannot multiply vectors of different lengths!")
    }
    let mut out: Vec<T> = Vec::with_capacity(v1.len());
    for i in 0..(v1.len()) {
        out.push(v1[i] * v2[i]);
    }
    out
}
Run Code Online (Sandbox Code Playgroud)

Fra*_*gné 7

在一个Vec或一个切片上使用索引器运算符时,编译器必须检查索引是在边界内还是在边界内.

但是,当您使用迭代器时,这些边界检查将被省略,因为迭代器已经过仔细编写以确保它们永远不会读出边界.此外,由于借用如何在Rust中工作,当迭代器存在于该数据结构上时(通过迭代器本身除外),数据结构不能被变异,因此在迭代期间有效边界不可能发生变化.

由于您同时迭代两个不同的数据结构,因此您将需要使用zip迭代器适配器.zip一个迭代器耗尽就停止,因此仍然需要验证两个向量是否具有相同的长度.zip生成元组的迭代器,其中每个元组包含两个原始迭代器中相同位置的项.然后,您可以使用map将每个元组转换为两个值的乘积.最后,你会希望collect通过所产生的新的迭代mapVec,然后可以从你的函数返回.collect使用size_hint预分配存储器用于使用矢量Vec::with_capacity.

/// element-wise multiplication for vecs
pub fn vec_mul<T>(v1: &[T], v2: &[T]) -> Vec<T>
where
    T: std::ops::Mul<Output = T> + Copy,
{
    if v1.len() != v2.len() {
        panic!("Cannot multiply vectors of different lengths!")
    }

    v1.iter().zip(v2).map(|(&i1, &i2)| i1 * i2).collect()
}
Run Code Online (Sandbox Code Playgroud)

注意:我已经更改了签名以获取切片而不是对向量的引用.请参阅为什么不鼓励接受对String(&String),Vec(&Vec)或Box(&Box)的引用作为函数参数?欲获得更多信息.

  • [`zip_eq`](https://docs.rs/itertools/0.8.0/itertools/trait.Itertools.html#method.zip_eq) (2认同)