我正在尝试并行运行一组作业。我想在自己的线程上运行每个任务,并在调用线程上收集响应。
有些工作可能需要比其他工作更长的时间,所以我想开始使用每个结果,而不必等待所有工作完成。
这是一次尝试:
struct Container<T> {
items : Vec<T>
}
#[derive(Debug)]
struct Item {
x: i32
}
impl Item {
fn foo (&mut self) {
self.x += 1; //consider an expensive mutating computation
}
}
fn main() {
use std;
use std::sync::{Mutex, Arc};
use std::collections::RingBuf;
//set up a container with 2 items
let mut item1 = Item { x: 0};
let mut item2 = Item { x: 1};
let container = Container { items: vec![item1, item2]};
//set a gather system for our results
let ringBuf = Arc::new(Mutex::new(RingBuf::<Item>::new()));
//farm out each job to its own thread...
for item in container.items {
std::thread::Thread::spawn(|| {
item.foo(); //job
ringBuf.lock().unwrap().push_back(item); //push item back to caller
});
}
loop {
let rb = ringBuf.lock().unwrap();
if rb.len() > 0 { //gather results as soon as they are available
println!("{:?}",rb[0]);
rb.pop_front();
}
}
}
对于初学者来说,由于不可穿透的cannot infer an appropriate lifetime due to conflicting requirements
错误而无法编译。
我做错了什么,我该怎么做?
答案 0 :(得分:2)
你有一些复合问题,但第一个问题是对Arc
的误用/误解。你需要给每个线程它自己的Arc
副本。 Arc
本身将确保更改同步。主要更改是添加了.clone()
和move
关键字:
for item in container.items {
let mrb = ringBuf.clone();
std::thread::Thread::spawn(move || {
item.foo(); //job
mrb.lock().unwrap().push_back(item); //push item back to caller
});
}
更改此内容之后,您将遇到一些关于遗忘mut
限定符的更简单错误,然后您遇到另一个问题 - 您尝试跨线程发送可变引用。您的for
循环需要返回&mut Item
才能致电foo
,但这与您的Vec
不符。改变它,我们可以得到编译的东西:
for mut item in container.items.into_iter() {
let mrb = ringBuf.clone();
std::thread::Thread::spawn(move || {
item.foo(); //job
mrb.lock().unwrap().push_back(item); //push item back to caller
});
}
在这里,我们使用输入向量,将每个Item
移动到工作线程。不幸的是,这会影响Playpen超时,所以可能存在一些更深层次的问题。
所有这一切,我强烈建议使用channel
s:
#![feature(std_misc)]
use std::sync::mpsc::channel;
#[derive(Debug)]
struct Item {
x: i32
}
impl Item {
fn foo(&mut self) { self.x += 1; }
}
fn main() {
let items = vec![Item { x: 0 }, Item { x: 1 }];
let rx = {
let (tx, rx) = channel();
for item in items.into_iter() {
let my_tx = tx.clone();
std::thread::Thread::spawn(move || {
let mut item = item;
item.foo();
my_tx.send(item).unwrap();
});
}
rx
};
for item in rx.iter() {
println!("{:?}", item);
}
}
这也在围栏中超时,但在编译和本地运行时工作正常。