The Rust Rand Book - Parallel RNGs has a very good summary about parallel RNGs. It also gives code examples using the rayon library. However, a few things to notice.
-
rand::ThreadRng (obtained by calling rand::thread_rng) is often used in code examples of parallel RNGs as it uses thread-local storage and is seeded automatically (lazily and uniquely) on each thread.
use rand::Rng; use rayon::prelude::*; let a: Vec<_> = (1i32..1_000_000) .into_par_iter() .map_init( || rand::thread_rng(), // get the thread-local RNG |rng, x| if rng.gen() { // randomly negate items -x } else { x }, ).collect();
While rand::ThreadRng is convenient to use as parallel RNGs, it is based on StdRng (currently, ChaCha block cipher with 12 rounds) which might be too slow for statistical simulations. If that's the case, you can use a faster RNG (e.g., SmallRng) with thread-local storage as parallel RNGs. Please refer to Customized RNGs with Thread-local Storage for details.
-
rayon::iter::ParallelIterator::map_init allows you do some initializing work before running each job. Note that the
init
closure passed tomap_init
is called once per rayon job NOT per rayon worker thead. A rayon worker thread typically executes many jobs. If you need to ensure some intializing work per rayon worker thread (e.g., if you want to use the same RNG for jobs executed by the same worker thread), you have to leverage thread-local storage in theinit
closure. For more discussions, please refer to Thread-Local Storage for Rayon . -
rayon::iter::ParallelIterator::with_min_len can be used to set the minimum number of items processed per job. When necessary, its parameter can be tuned to improve performance.
Customized RNGs with Thread-local Storage
Please refer to Thread-Local Storage for Rayon for detailed discussions.