Rust 如何进行数据并行图像处理?
我正在尝试用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;
/// 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