Multithreading 作业的拆分/聚集模式
我有一套工作,我正试图并行运行。我想在自己的线程上运行每个任务,并在调用线程上收集响应 有些作业可能需要比其他作业更长的时间,因此我希望在收到每个结果时就开始使用它,而不必等待所有作业完成 以下是一个尝试:Multithreading 作业的拆分/聚集模式,multithreading,rust,Multithreading,Rust,我有一套工作,我正试图并行运行。我想在自己的线程上运行每个任务,并在调用线程上收集响应 有些作业可能需要比其他作业更长的时间,因此我希望在收到每个结果时就开始使用它,而不必等待所有作业完成 以下是一个尝试: struct Container<T> { items : Vec<T> } #[derive(Debug)] struct Item { x: i32 } impl Item { fn foo (&mut self) {
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();
}
}
}
struct容器{
项目:Vec
}
#[导出(调试)]
结构项{
x:i32
}
impl项目{
fn-foo(&mut-self){
self.x+=1;//考虑一个昂贵的变异计算
}
}
fn main(){
使用性病;
使用std::sync::{Mutex,Arc};
使用std::collections::RingBuf;
//设置一个包含2个项目的容器
设mut item1=Item{x:0};
设mut item2=Item{x:1};
让container=container{items:vec![item1,item2]};
//为我们的结果设置一个收集系统
让ringBuf=Arc::new(Mutex::new(ringBuf:::new());
//将每个作业分配到自己的线程。。。
对于容器中的项目。项目{
std::thread::thread::spawn(| |{
item.foo();//作业
ringBuf.lock().unwrap().push_back(项);//将项推回调用方
});
}
环路{
设rb=ringBuf.lock().unwrap();
如果rb.len()>0{//,则在结果可用时立即收集它们
println!(“{:?}”,rb[0]);
rb.pop_front();
}
}
}
对于初学者来说,这不会编译,因为无法穿透的无法推断出合适的生存期,因为存在冲突的需求错误
我做错了什么?我如何做才是对的?你有几个复杂的问题,但第一个问题是对Arc的误用/误解。您需要为每个线程提供它自己的Arc
副本<代码>Arc
本身将确保更改同步。主要更改是添加了.clone()
和移动
关键字:
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
});
}
这里,我们使用输入向量,将每个项
移动到工作线程。不幸的是,这会导致Playpen超时,因此可能存在更深层次的问题
综上所述,我强烈建议使用s:
这也会在playpen中超时,但在本地编译和运行时效果良好
#![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);
}
}