multithreadingrustrayon

Is rayon's parallelism limited to the cores of the machine?


I have the following toy Rust program:

use rayon::prelude::*;
use std::{env, thread, time};

/// Sleeps 1 second n times
fn seq_sleep(n: usize) {
    for _ in 0..n {
        thread::sleep(time::Duration::from_millis(1000));
    }
}

/// Launches n threads that sleep 1 second
fn thread_sleep(n: usize) {
    let mut handles = Vec::new();
    for _ in 0..n {
        handles.push(thread::spawn(|| {
            thread::sleep(time::Duration::from_millis(1000))
        }));
    }
    for handle in handles {
        handle.join().unwrap();
    }
}

/// Sleeps 1 seconds n times parallely using rayon
fn rayon_sleep(n: usize) {
    let millis = vec![0; n];
    millis
        .par_iter()
        .for_each(|_| thread::sleep(time::Duration::from_millis(1000)));
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let n = args[1].parse::<usize>().unwrap();

    let now = time::Instant::now();
    seq_sleep(n);
    println!("sequential: {:?}", now.elapsed());

    let now = time::Instant::now();
    thread_sleep(n);
    println!("thread: {:?}", now.elapsed());

    let now = time::Instant::now();
    rayon_sleep(n);
    println!("rayon: {:?}", now.elapsed());
}

Basically, I want to compare the degree of parallelism of i) sequential code, ii) basic threads, and iii) rayon. To do so, my program accepts one input parameter n and, depending on the method, it sleeps for 1 second n times. For n = 8, I get the following output:

sequential: 8.016809707s
thread: 1.006029845s
rayon: 1.004957395s

So far so good. However, for n = 9, I get the following output:

sequential: 9.012422104s
thread: 1.003085005s
rayon: 2.011378713s

The sequential and basic thread versions make sense to me. However, I expected rayon to take 1 second. My machine has 4 cores and hyper threading. This leads me to think that rayon internally limits the number of parallel threads according to the cores/threads that your machine supports. Is this correct?


Solution

  • Yes:

    rayon::ThreadPoolBuilder::build_global():

    Initializes the global thread pool. This initialization is optional. If you do not call this function, the thread pool will be automatically initialized with the default configuration.

    rayon::ThreadPoolBuilder::num_threads():

    If num_threads is 0, or you do not call this function, then the Rayon runtime will select the number of threads automatically. At present, this is based on the RAYON_NUM_THREADS environment variable (if set), or the number of logical CPUs (otherwise). In the future, however, the default behavior may change to dynamically add or remove threads as needed.