简体   繁体   中英

What is the Rust idiom for turning a bunch of tasks into futures that are executed on a thread pool?

In java I would use an ExecutorService that is a thread pool with a fixed size and submit(Callable) s to it and then get() the results.

What is the idiom that matches this in Rust? I could thread::spawn() a bunch of tasks and join() them, but it would create a thread per task, and I want to limit the number of concurrent threads.

In order to make things a little more concrete, here is a rough sketch of some code:

let a4 = thread_pool.spawn(|| svg.compute_stitches("path674"));
let a1 = thread_pool.spawn(|| svg.compute_stitches("path653"));
let a2 = thread_pool.spawn(|| svg.compute_stitches("g659"));
let a3 = thread_pool.spawn(|| svg.compute_stitches("path664"));
let a5 = thread_pool.spawn(|| svg.compute_stitches("path679"));

stitcher.stitch(a1.join());
stitcher.stitch(a2.join());
stitcher.next_color();
stitcher.stitch(a3.join());
stitcher.next_color();
stitcher.stitch(a4.join());
stitcher.next_color();
stitcher.stitch(a5.join());

I have rolled my own solution for the time being. It looks like this:

use std::sync::mpsc;
use std::sync::mpsc::{Receiver, RecvError};
use std::{panic, thread};

pub struct ThreadPool {
    channel: spmc::Sender<Mission>,
}

impl ThreadPool {
    pub fn new(thread_count: usize) -> ThreadPool {
        let (tx, rx) = spmc::channel();

        for _ in 0..thread_count {
            let rx2 = rx.clone();
            thread::spawn(move || Self::work_loop(rx2));
        }

        ThreadPool { channel: tx }
    }

    pub fn spawn<F, T: 'static>(&mut self, task: F) -> Answer<T>
    where
        F: FnOnce() -> T + std::panic::UnwindSafe + Send + 'static,
    {
        let (tx, rx) = mpsc::channel();

        let mission = Mission {
            go: Box::new(move || {
                let tmp = panic::catch_unwind(task);
                tx.send(tmp).unwrap()
            }),
        };

        self.channel.send(mission).unwrap();

        Answer { channel: rx }
    }

    fn work_loop(channel: spmc::Receiver<Mission>) {
        while let Ok(mission) = channel.recv() {
            (mission.go)();
        }
    }
}

struct Mission {
    go: Box<dyn FnOnce()>,
}

unsafe impl Send for Mission {}

pub struct Answer<T> {
    channel: Receiver<std::thread::Result<T>>,
}

impl<T> Answer<T> {
    pub fn get(self) -> Result<T, RecvError> {
        let tmp = self.channel.recv();

        match tmp {
            Ok(rval) => match rval {
                Ok(rval) => Ok(rval),
                Err(explosion) => panic::resume_unwind(explosion),
            },
            Err(e) => Err(e),
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM