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);
    }
}