1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//! Utility methods to spawn a number of
//! [scoped](https://doc.rust-lang.org/stable/std/thread/fn.scope.html)
//! threads equals to the number of cores on the machine. Unlike normal threads, scoped threads
//! can borrow data from their environment.
use std::thread::*;

/// Spawn `n` scoped threads, where `n` is the available parallelism.
pub fn spawn<F, T>(f: F)
where
    F: FnOnce() -> T + Copy + Send,
    T: Send,
{
    scope(|scope| {
        for _ in 0..threads() {
            scope.spawn(f);
        }
    });
}

/// Splits `items` into batches, one per thread. Items are assigned in a round robin fashion,
/// to achieve a crude load balacing in case some items are more complex to process than others.
pub fn spawn_batches<F, T, U>(mut items: Vec<U>, f: F)
where
    F: FnOnce(Vec<U>) -> T + Copy + Send,
    T: Send,
    U: Send,
{
    let threads = threads();
    let mut batches: Vec<_> = (0..threads).map(|_| Vec::new()).collect();
    let mut index = 0;

    // Round robin items over each thread.
    while let Some(next) = items.pop() {
        batches[index % threads].push(next);
        index += 1;
    }

    scope(|scope| {
        for batch in batches {
            scope.spawn(move || f(batch));
        }
    });
}

fn threads() -> usize {
    available_parallelism().unwrap().get()
}