Skip to main content

orx_parallel/runner/
new_runner.rs

1use crate::ThreadPool;
2use crate::pools::DefaultPool;
3use crate::pools::global_pool;
4#[cfg(feature = "std")]
5use crate::runner::runner_variants::AdaptiveChunkRunner;
6use crate::runner::runner_variants::FixedChunkRunner;
7
8/// Entry point for creating parallel runners that control how work is distributed across threads.
9///
10/// A runner is passed to `.runner(...)` on a parallel iterator to select the execution strategy.
11///
12/// > **Note:** `Runner` is a convenience factory for the runners provided by this crate.
13/// > You can also implement a compatible runner type yourself and pass it directly to `.runner(...)` —
14/// > the transformation accepts any type that satisfies the trait.
15///
16/// # Examples
17///
18/// ```rust
19/// use orx_parallel::*;
20///
21/// let par = (0..100).par().map(|x| x + 1);
22/// let par = par.runner(Runner::fixed());
23/// let sum = par.sum();
24///
25/// let par = (0..100).par().map(|x| x + 1);
26/// #[cfg(feature = "std")]
27/// let par = par.runner(Runner::adaptive());
28/// let sum = par.sum();
29/// ```
30pub struct Runner;
31
32impl Runner {
33    /// Creates a runner that splits work into fixed-size chunks ahead of time.
34    ///
35    /// This is the default strategy: the input is divided into equal chunks, one per thread.
36    /// It has low overhead and works well when tasks have uniform cost.
37    ///
38    /// # Example
39    ///
40    /// ```
41    /// use orx_parallel::*;
42    ///
43    /// let par = (0..100).par().map(|x| x + 1);
44    /// let par = par.runner(Runner::fixed());
45    ///
46    /// let result: Vec<_> = par.collect();
47    /// ```
48    pub fn fixed() -> FixedChunkRunner<DefaultPool> {
49        FixedChunkRunner::new(global_pool())
50    }
51
52    /// Creates a fixed chunk runner backed by `pool`.
53    ///
54    /// Use this when a computation should use a specific thread pool instead of the global
55    /// default pool. The returned runner keeps the fixed-size chunking strategy of
56    /// [`Self::fixed`] while delegating execution to the provided pool.
57    ///
58    /// # Example
59    ///
60    /// ```
61    /// use orx_parallel::*;
62    ///
63    /// let par = (0..100).par();
64    ///
65    /// #[cfg(feature = "std")]
66    /// let par = par.runner(Runner::fixed_with_pool(Pool::basic(4)));
67    ///
68    /// let result: Vec<_> = par.collect();
69    /// ```
70    pub fn fixed_with_pool<P: ThreadPool>(pool: P) -> FixedChunkRunner<P> {
71        FixedChunkRunner::new(pool)
72    }
73
74    /// Creates an adaptive chunk runner.
75    ///
76    /// This strategy explores and selects chunk sizes based on observed runtime behavior.
77    ///
78    /// # Example
79    ///
80    /// ```
81    /// use orx_parallel::*;
82    ///
83    /// let par = (0..100).par().map(|x| x + 1);
84    ///
85    /// #[cfg(feature = "std")]
86    /// let par = par.runner(Runner::adaptive());
87    ///
88    /// let result: Vec<_> = par.collect();
89    /// ```
90    #[cfg(feature = "std")]
91    pub fn adaptive() -> AdaptiveChunkRunner<DefaultPool> {
92        AdaptiveChunkRunner::new(global_pool())
93    }
94
95    /// Creates an adaptive chunk runner backed by `pool`.
96    ///
97    /// Use this when a computation should combine a specific thread pool with adaptive chunk
98    /// sizing. The returned runner keeps the adaptive strategy of [`Self::adaptive`] while
99    /// delegating execution to the provided pool.
100    ///
101    /// # Example
102    ///
103    /// ```
104    /// use orx_parallel::*;
105    ///
106    /// let pool = Pool::once(4);
107    /// let par = (0..100).par().runner(Runner::adaptive_with_pool(pool));
108    ///
109    /// let result: Vec<_> = par.collect();
110    /// ```
111    #[cfg(feature = "std")]
112    pub fn adaptive_with_pool<P: ThreadPool>(pool: P) -> AdaptiveChunkRunner<P> {
113        AdaptiveChunkRunner::new(pool)
114    }
115}