orx_parallel/parameters/
num_threads.rs

1use std::num::NonZeroUsize;
2
3/// `NumThreads` represents the degree of parallelization. It is possible to define an upper bound on the number of threads to be used for the parallel computation.
4/// When set to **1**, the computation will be executed sequentially without any overhead.
5/// In this sense, parallel iterators defined in this crate are a union of sequential and parallel execution.
6///
7/// # Rules of Thumb / Guidelines
8///
9/// It is recommended to set this parameter to its default value, `NumThreads::Auto`.
10/// This setting assumes that it can use all available threads; however, the computation will spawn new threads only when required.
11/// In other words, when we can dynamically decide that the task is not large enough to justify spawning a new thread, the parallel execution will avoid it.
12///
13/// A special case is `NumThreads::Max(NonZeroUsize::new(1).unwrap())`, or equivalently `NumThreads::sequential()`.
14/// This will lead to a sequential execution of the defined computation on the main thread.
15/// Both in terms of used resources and computation time, this mode is not similar but **identical** to a sequential execution using the regular sequential `Iterator`s.
16///
17/// Lastly, `NumThreads::Max(t)` where `t >= 2` can be used in the following scenarios:
18/// * We have a strict limit on the resources that we can use for this computation, even if the hardware has more resources.
19///   Parallel execution will ensure that `t` will never be exceeded.
20/// * We have a computation which is extremely time-critical and our benchmarks show that `t` outperforms the `NumThreads::Auto` on the corresponding system.
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
22pub enum NumThreads {
23    /// This setting assumes that it can use all available threads; however, the computation will spawn new threads only when required.
24    /// In other words, when we can dynamically decide that the task is not large enough to justify spawning a new thread, the parallel execution will avoid it.
25    #[default]
26    Auto,
27    /// Limits the maximum number of threads that can be used by the parallel execution.
28    ///
29    /// A special case is `NumThreads::Max(NonZeroUsize::new(1).unwrap())`, or equivalently `NumThreads::sequential()`.
30    /// This will lead to a sequential execution of the defined computation on the main thread.
31    /// Both in terms of used resources and computation time, this mode is not similar but **identical** to a sequential execution using the regular sequential `Iterator`s.
32    ///
33    /// Lastly, `NumThreads::Max(t)` where `t >= 2` can be used in the following scenarios:
34    /// * We have a strict limit on the resources that we can use for this computation, even if the hardware has more resources.
35    ///   Parallel execution will ensure that `t` will never be exceeded.
36    /// * We have a computation which is extremely time-critical and our benchmarks show that `t` outperforms the `NumThreads::Auto` on the corresponding system.
37    Max(NonZeroUsize),
38}
39
40const SEQUENTIAL_NUM_THREADS: NonZeroUsize = NonZeroUsize::new(1).expect("seq=1 is positive");
41
42impl From<usize> for NumThreads {
43    /// Converts the nonnegative integer to number of threads as follows:
44    ///
45    /// * 0 is converted to `NumThreads::Auto`,
46    /// * `n` is converted to `NumThreads::Max(n)` where `n > 0`.
47    fn from(value: usize) -> Self {
48        match value {
49            0 => Self::Auto,
50            n => Self::Max(NonZeroUsize::new(n).expect("must be positive")),
51        }
52    }
53}
54
55impl NumThreads {
56    /// Equivalent to `NumThreads::Max(NonZeroUsize::new(1).unwrap())`.
57    ///
58    /// This will lead to a sequential execution of the defined computation on the main thread.
59    /// Both in terms of used resources and computation time, this mode is not similar but **identical** to a sequential execution using the regular sequential `Iterator`s.
60    pub const fn sequential() -> Self {
61        NumThreads::Max(SEQUENTIAL_NUM_THREADS)
62    }
63
64    /// Returns true if number of threads is set to 1.
65    ///
66    /// Note that in this case the computation will be executed sequentially using regular iterators.
67    pub fn is_sequential(self) -> bool {
68        matches!(self, Self::Max(n) if n == SEQUENTIAL_NUM_THREADS)
69    }
70}