Rust 如何进行数据并行图像处理?

Rust 如何进行数据并行图像处理?,rust,Rust,我正在尝试用Rust编写一个简单的数据并行图像处理过滤器。 我用下面的代码在单线程中运行它 /// an example of a very simple filter fn modular_filter_chunk(input: &[u16], slice_width: usize, slice_height: usize, mod_value: u16, output: &mut[u16]) { let size = slice_width*slice_height;

我正在尝试用Rust编写一个简单的数据并行图像处理过滤器。 我用下面的代码在单线程中运行它

/// an example of a very simple filter
fn modular_filter_chunk(input: &[u16], slice_width: usize, slice_height: usize, mod_value: u16, output: &mut[u16]) {
    let size = slice_width*slice_height;
    for i in 0..size {
        output[i] = input[i] % mod_value;
    }
}

fn modular_filter_multi(input: &Vec<u16>, width: usize, height: usize, slice_num: usize, mod_value: u16, output: &mut Vec<u16>) {
    // divide image vertically to slices
    let height_per_slice = height / slice_num;
    let size_per_chunk = height_per_slice * width;
    let in_itr = input.chunks(size_per_chunk);
    let out_itr = output.chunks_mut(size_per_chunk);
    for (input, output) in in_itr.zip(out_itr) {
        modular_filter_chunk(input, width, height_per_slice, mod_value, output);
    }
}

fn main() {
    let width: usize = 1024;
    let height: usize = 1024;
    let input = vec![1234; width*height];
    let mut output = vec![0; width*height];
    modular_filter_multi(&input, width, height, 4, 73, &mut output);
}
编译错误消息
如何更改代码以使过滤器并行工作?

好的,我通过以下步骤使其工作

  • 每晚安装一次
  • 添加
    #![功能(范围)]
    到源代码顶部
  • 使用以下代码替换
    modular\u filter\u块
    for循环

    let mut handles = Vec::new();
    for (input, output) in in_itr.zip(out_itr) {
        let h = std::thread::scoped(move || {
            modular_filter_chunk(input, width, height_per_slice, mod_value, output);
        });
        handles.push(h);
    }
    for handle in handles {
        handle.join();
    }
    

  • 我最初认为
    thread::scoped
    可能是一个解决方案,但由于它不稳定,我无法编译它。我想知道是否有一种方法可以在不使用
    thread::scoped
    safe
    的情况下解决此问题,让我们看看签名:

    pub-fn-spawn(f:f)->JoinHandle
    其中F:FnOnce()->T,
    F:发送+'静态,
    T:发送+'静态
    
    这表明
    spawn
    采用实现
    FnOnce
    (将被精确调用一次)的类型
    F
    ,调用时将返回
    T
    类型的内容。类型
    F
    T
    必须实现
    Send
    ,并且必须至少具有生存期
    “static

    绑定将可能的类型限制为“能够跨线程边界传输的类型”,并且
    'static
    意味着该类型中的任何引用必须在程序的整个生命周期内有效,从
    main
    开始之前到
    main
    退出之后

    这就解释了您收到的错误消息:您的任何引用都不能保证在程序的整个生命周期内有效。事实上,他们肯定不会活那么久

    当您
    spawn
    一个线程时,新线程不再与产生它的线程有任何具体的连接。新线程很可能比父线程寿命长!如果在父线程死亡后尝试使用引用,这将导致非常糟糕的事情发生

    正如您所发现的,
    thread::scoped
    提供了一个解决方案。作用域线程需要在其包含的任何引用过期之前联接然而,作用域线程不稳定的原因是:它们是不稳定的。有一个很好的方法把它带回来,但是有一些很深的细节,所以它被推迟了


    正如所述,您可以使用安全地共享稳定数据库中的不可变数据。不过,您需要使用共享可变输出缓冲区。你可以知道为什么人们对恢复
    thread::scoped
    感到兴奋

    请创建一个。我敢打赌,一个小得多的例子会重现同样的问题。你有没有看过其他有相同错误信息的问题?这和那些有什么不同?你试过按照错误信息告诉你的去做吗?就目前而言,您的问题并没有显示出为解决您自己的问题所做的太多努力。@rillomas Yeas,您应该使问题变得更小,这样可以更容易地发现问题,下面是您的代码的一个最小版本,例如:我认为它可以重现您的问题。如果确实如此,用它编辑你的问题肯定会有助于使问题更容易回答。好的,我更新了一个较小的例子。我会看看我是否能自己解决这个问题,但我会把问题公布出来,看看是否有人能给我帮助。你可以通过将所有数据(真正的所有者,而不仅仅是借用的指针)保存在
    Arc
    对象内的结构中来避免使用
    scope
    ,这样就可以满足
    thread::spawn
    的静态生存期要求。是的,我也考虑过这个问题,但我相信使用
    Arc
    Mutex
    只允许一个线程一次处理图像。我想要的是来自多个线程的同时处理(并行处理),所以我不能使用
    Arc
    Mutex
    。您不需要Mutex:)Mutex是为了防止同时访问,而你需要的恰恰相反——用多个线程同时处理同一个向量。我认为你可以在不使用
    互斥体的情况下共享输入(因为它不会发生变异),但是你不需要输出
    互斥体吗?我认为Rust禁止共享可变数据。感谢您澄清背景!我以前也看到过与作用域线程相关的问题,因为解决这个问题似乎需要一些时间,所以我正在寻找一种不使用作用域线程的方法。也许我会看看一个更完善的fork-join库。
    
    src\main.rs:25:21: 25:43 error: cannot infer an appropriate lifetime for lifetime parameter 'a in function call due to c
    onflicting requirements
    src\main.rs:25  let in_itr = input.chunks(size_per_chunk);
                                       ^~~~~~~~~~~~~~~~~~~~~~
    src\main.rs:27:25: 27:44 note: first, the lifetime cannot outlive the method call at 27:24...
    src\main.rs:27  for (input, output) in in_itr.zip(out_itr) {
                                           ^~~~~~~~~~~~~~~~~~~
    note: in expansion of for loop expansion
    src\main.rs:27:2: 29:3 note: expansion site
    src\main.rs:27:25: 27:31 note: ...so that method receiver is valid for the method call
    src\main.rs:27  for (input, output) in in_itr.zip(out_itr) {
                                           ^~~~~~
    note: in expansion of for loop expansion
    src\main.rs:27:2: 29:3 note: expansion site
    src\main.rs:25:15: 25:20 note: but, the lifetime must be valid for the expression at 25:14...
    src\main.rs:25  let in_itr = input.chunks(size_per_chunk);
                                 ^~~~~
    src\main.rs:25:15: 25:20 note: ...so that pointer is not dereferenced outside its lifetime
    src\main.rs:25  let in_itr = input.chunks(size_per_chunk);
                                 ^~~~~
    error: aborting due to previous error
    Could not compile `rust_multithread`.
    
    let mut handles = Vec::new();
    for (input, output) in in_itr.zip(out_itr) {
        let h = std::thread::scoped(move || {
            modular_filter_chunk(input, width, height_per_slice, mod_value, output);
        });
        handles.push(h);
    }
    for handle in handles {
        handle.join();
    }
    
    pub fn spawn<F, T>(f: F) -> JoinHandle<T>
        where F: FnOnce() -> T,
              F: Send + 'static,
              T: Send + 'static