假设我们希望将向量的每个切片中的每个元素加倍(原地),其中切片由一对(开始,结束)位置的列表定义.下面的代码以习惯用法表达了intent,但由于parallel for_each内部的vector的可变borrow 而无法编译:

use rayon::prelude::*;

fn main() {
    let mut data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let slice_pairs = vec![(0, 3), (4, 7), (8, 10)];

    slice_pairs.into_par_iter().for_each(|(start, end)| {
        let slice = &mut data[start..end];
        for elem in slice.iter_mut() {
            *elem *= 2;
        }
    });

    println!("{:?}", data);
}

这里有一个真正的潜在数据竞争—为了排除它们,您需要判断切片是否重叠.问题是在Rust中最好的方式是什么,通过不安全的代码或安全的API.下面的代码使用unsafe来"继续做这个";我的问题是是否有比下面更好的方法(它将向量的基指针转换为i64,并返回到"盲目"借位判断器的问题).

use rayon::prelude::*;
use std::mem;

fn main() {
    let mut data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let slice_pairs = vec![(0, 4), (4, 7), (7, 10)];

    let ptr_outer = data.as_mut_ptr();
    let ptr_int : i64 = unsafe { mem::transmute(ptr_outer) };

    slice_pairs.into_par_iter().for_each(|(start, end)| {
        unsafe {
            let ptr : *mut i32 = mem::transmute(ptr_int);
            let slice = std::slice::from_raw_parts_mut(ptr.add(start), end - start);

            for elem in slice.iter_mut() {
                *elem *= 2;
            }
        }
    });

    println!("{:?}", data);
}

推荐答案

我建议首先将slice_pairs转换为一系列可变切片,然后并行使用所有这些切片.

Subdividing a whole slice into multiple independent sub-slices (from the borrow-checker's point of view) can be done with slice::split_at_mut().
Of course, the indices in slice_pairs must be ordered and must not overlap, for these sub-slices to be correct.

Note that I tried to use .map().collect(), instead of an explicit loop with .push(), in order to build the sequence of slices, but I failed...
The compiler said that the FnMut closure in .map() could not return a reference; may be someone could fix my code...

use rayon::prelude::*;

fn main() {
    let mut data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let slice_pairs = vec![(0, 3), (4, 7), (8, 10)];

    // build a sequence of mutable slices
    let mut slices = Vec::with_capacity(slice_pairs.len());
    let mut remaining = data.as_mut_slice();
    let mut idx = 0;
    for (start, end) in slice_pairs {
        let (_skip, tail) = remaining.split_at_mut(start - idx);
        let (sl, tail) = tail.split_at_mut(end - start);
        remaining = tail;
        idx = end;
        slices.push(sl);
    }
    println!("slices: {:?}", slices);

    // parallel usage of the mutable slices
    slices.into_par_iter().for_each(|sl| {
        for elem in sl.iter_mut() {
            *elem *= 2;
        }
    });

    println!("data: {:?}", data);
}
/*
slices: [[1, 2, 3], [5, 6, 7], [9, 10]]
data: [2, 4, 6, 4, 10, 12, 14, 8, 18, 20]
*/

Rust相关问答推荐

Rust kill std::processs::child

Rust中的相互递归特性与默认实现

有没有办法在Rust中配置常量变量的值?

如何go 除铁 rust 中路径组件的第一项和最后一项?

在自定义序列化程序中复制serde(With)的行为

RUST应用程序正在退出,错误代码为:(退出代码:0xc0000005,STATUS_ACCESS_VIOLATION)

无符号整数的Rust带符号差

有没有一种方法可以创建一个闭包来计算Rust中具有随机系数的n次多项式?

确保参数是编译时定义的字符串文字

我可以解构self 参数吗?

为什么某些类型参数仅在特征边界中使用的代码在没有 PhantomData 的情况下进行编译?

Button.set_hexpand(false) 不会阻止按钮展开

Rust:为什么 Pin 必须持有指针?

如何将 C++ 程序链接到 Rust 程序,然后将该 Rust 程序链接回 C++ 程序? (cpp -> rust -> cpp)

是否可以在 Rust 中的特定字符上实现特征?

如何创建递归borrow 其父/创建者的 struct ?

在 Rust 中为泛型 struct 编写一次特征绑定

有没有办法阻止 rust-analyzer 使非活动代码变暗?

需要括号的宏调用中的不必要的括号警告 - 这是编写宏的糟糕方法吗?

如何将 u8 切片复制到 u32 切片中?