from forkunion import CacheAligned4.0.0-rc.1 · d927445f
For Rayon-style ergonomics, use the parallel iterator API with the prelude.
Unlike Rayon, ForkUnion’s parallel iterators don’t depend on the global state and allow explicit control over the thread pool and scheduling strategy.
For statically shaped workloads, the default static scheduling is more efficient:
use forkunion as fu;use forkunion::prelude::*;let topology = fu::Topology::new().expect("Failed to detect hardware topology");let mut pool = fu::spawn(&topology, 4);let mut data: Vec<usize> = (0..1000).collect();(&data[..]) .into_par_iter() .with_pool(&mut pool) .for_each(|value, _task, _at| { println!("Value: {}", value); })?;
For dynamic work-stealing, use with_schedule with DynamicScheduler:
Beyond reductions, the iterators offer short-circuiting searches - find_first and find_last for the deterministic lowest- or highest-index match, find_any for whichever match is found first with cooperative cancellation, and any / all for boolean predicates that stop the moment the answer is known.
Fallible bodies get for_each_fallible and fold_with_scratch_fallible, which propagate the first error and signal the other workers to stop.
Their two answers stay apart: the outer Result reports whether the dispatch ran, the inner one whether the caller’s own work succeeded, so the caller’s error type carries no constraint.
This Rayon-style layer is Rust-only; C, C++, Zig, and Mojo expose the pool primitives for_threads, for_n, for_n_dynamic, and for_slices directly.
Zig additionally mirrors Rust’s for_slices_mut as forSlicesMut, which hands each thread a disjoint sub-slice rather than the TasksRange its indices would form.
API
StructCacheAlignedPads a value out to a full DEFAULT_ALIGNMENT so per-thread slots never false-share.1
Allocate one per thread as scratch, then combine after the parallel region. The padding is
what makes an array of these stride by a whole line, which is the property that matters.