Iterators
The functional programming paradigm does not have quite as many problems with synchronisation because it solves the problem of mutability by encapsulating it. You can see this in the restrictions that iterators in Rust have: They borrow the whole collection while iterating, making it impossible to access otherwise. Also, it's not possible to access any other element than the one you're currently at while iterating. This means that if you don't access anything else that needs synchronisation while iterating, the iteration can inherently be done in parallel. This is how functional languages can introduce trivial concurrency.
Rust's type system allows the same for iterators, since they are essentially are a library feature. However, iterators in the standard library don't support concurrency, so you will have to resort to an external one. We're now taking a brief look on the rayon
crate since it's the de-facto standard for parallel iteration in Rust.
It also has some additional features, but parallel iteration is the core.
Rayon provides both a global thread pool and traits for parallel iteration. They have some additional restrictions, for example, closures of non-collecting iterator methods can only immutably borrow variables with Sync
from their context, moving non-Copy
variables is also not allowed.
If these conditions are fulfilled, you can simply call par_iter
on any collection implementing them to get a ParallelIterator
. You can then use it just like a normal iterator, but it will run in parallel if it makes sense to do so.
You might not be able to use all iterator functions you know from the standard library, but it captures the majority of use cases.
That's basically it, apart from a code example to finish it off:
use rayon::prelude::*; fn main() { let mut v: Vec<usize> = (0..65535).into_iter().collect(); // hidden call to deref_mut v.sort_unstable(); v.as_mut_slice().sort_unstable(); // parallel sorting v.as_parallel_slice_mut().sort_unstable(); let sum: usize = v.iter().map(|i| i + 2).sum(); // parallel execution let parallel_sum: usize = v.par_iter().map(|i| i + 2).sum(); println!("Sum: {}", sum); println!("Parallel sum: {}", parallel_sum); }