分割/收集工作模式

时间:2015-02-16 14:21:31

标签: multithreading rust

我正在尝试并行运行一组作业。我想在自己的线程上运行每个任务,并在调用线程上收集响应。

有些工作可能需要比其他工作更长的时间,所以我想开始使用每个结果,而不必等待所有工作完成。

这是一次尝试:

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错误而无法编译。

我做错了什么,我该怎么做?

1 个答案:

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

这也在围栏中超时,但在编译和本地运行时工作正常。