//! Rayon-core houses the core stable APIs of Rayon. //! //! These APIs have been mirrored in the Rayon crate and it is recommended to use these from there. //! //! [`join`] is used to take two closures and potentially run them in parallel. //! - It will run in parallel if task B gets stolen before task A can finish. //! - It will run sequentially if task A finishes before task B is stolen and can continue on task B. //! //! [`scope`] creates a scope in which you can run any number of parallel tasks. //! These tasks can spawn nested tasks and scopes, but given the nature of work stealing, the order of execution can not be guaranteed. //! The scope will exist until all tasks spawned within the scope have been completed. //! //! [`spawn`] add a task into the 'static' or 'global' scope, or a local scope created by the [`scope()`] function. //! //! [`ThreadPool`] can be used to create your own thread pools (using [`ThreadPoolBuilder`]) or to customize the global one. //! Tasks spawned within the pool (using [`install()`], [`join()`], etc.) will be added to a deque, //! where it becomes available for work stealing from other threads in the local threadpool. //! //! [`join`]: fn.join.html //! [`scope`]: fn.scope.html //! [`scope()`]: fn.scope.html //! [`spawn`]: fn.spawn.html //! [`ThreadPool`]: struct.threadpool.html //! [`install()`]: struct.ThreadPool.html#method.install //! [`spawn()`]: struct.ThreadPool.html#method.spawn //! [`join()`]: struct.ThreadPool.html#method.join //! [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html //! //! # Global fallback when threading is unsupported //! //! Rayon uses `std` APIs for threading, but some targets have incomplete implementations that //! always return `Unsupported` errors. The WebAssembly `wasm32-unknown-unknown` and `wasm32-wasi` //! targets are notable examples of this. Rather than panicking on the unsupported error when //! creating the implicit global threadpool, Rayon configures a fallback mode instead. //! //! This fallback mode mostly functions as if it were using a single-threaded "pool", like setting //! `RAYON_NUM_THREADS=1`. For example, `join` will execute its two closures sequentially, since //! there is no other thread to share the work. However, since the pool is not running independent //! of the main thread, non-blocking calls like `spawn` may not execute at all, unless a lower- //! priority call like `broadcast` gives them an opening. The fallback mode does not try to emulate //! anything like thread preemption or `async` task switching, but `yield_now` or `yield_local` //! can also volunteer execution time. //! //! Explicit `ThreadPoolBuilder` methods always report their error without any fallback. //! //! # Restricting multiple versions //! //! In order to ensure proper coordination between threadpools, and especially //! to make sure there's only one global threadpool, `rayon-core` is actively //! restricted from building multiple versions of itself into a single target. //! You may see a build error like this in violation: //! //! ```text //! error: native library `rayon-core` is being linked to by more //! than one package, and can only be linked to by one package //! ``` //! //! While we strive to keep `rayon-core` semver-compatible, it's still //! possible to arrive at this situation if different crates have overly //! restrictive tilde or inequality requirements for `rayon-core`. The //! conflicting requirements will need to be resolved before the build will //! succeed.
use std::any::Any; use std::env; use std::error::Error; use std::fmt; use std::io; use std::marker::PhantomData; use std::str::FromStr; use std::thread;
#[macro_use] mod private;
mod broadcast; mod job; mod join; mod latch; mod registry; mod scope; mod sleep; mod spawn; mod thread_pool; mod unwind;
/// Returns the maximum number of threads that Rayon supports in a single thread-pool. /// /// If a higher thread count is requested by calling `ThreadPoolBuilder::num_threads` or by setting /// the `RAYON_NUM_THREADS` environment variable, then it will be reduced to this maximum. /// /// The value may vary between different targets, and is subject to change in new Rayon versions. pubfn max_num_threads() -> usize { // We are limited by the bits available in the sleep counter's `AtomicUsize`. crate::sleep::THREADS_MAX
}
/// Returns the number of threads in the current registry. If this /// code is executing within a Rayon thread-pool, then this will be /// the number of threads for the thread-pool of the current /// thread. Otherwise, it will be the number of threads for the global /// thread-pool. /// /// This can be useful when trying to judge how many times to split /// parallel work (the parallel iterator traits use this value /// internally for this purpose). /// /// # Future compatibility note /// /// Note that unless this thread-pool was created with a /// builder that specifies the number of threads, then this /// number may vary over time in future versions (see [the /// `num_threads()` method for details][snt]). /// /// [snt]: struct.ThreadPoolBuilder.html#method.num_threads pubfn current_num_threads() -> usize { crate::registry::Registry::current_num_threads()
}
/// Error when initializing a thread pool. #[derive(Debug)] pubstruct ThreadPoolBuildError {
kind: ErrorKind,
}
/// Used to create a new [`ThreadPool`] or to configure the global rayon thread pool. /// ## Creating a ThreadPool /// The following creates a thread pool with 22 threads. /// /// ```rust /// # use rayon_core as rayon; /// let pool = rayon::ThreadPoolBuilder::new().num_threads(22).build().unwrap(); /// ``` /// /// To instead configure the global thread pool, use [`build_global()`]: /// /// ```rust /// # use rayon_core as rayon; /// rayon::ThreadPoolBuilder::new().num_threads(22).build_global().unwrap(); /// ``` /// /// [`ThreadPool`]: struct.ThreadPool.html /// [`build_global()`]: struct.ThreadPoolBuilder.html#method.build_global pubstruct ThreadPoolBuilder<S = DefaultSpawn> { /// The number of threads in the rayon thread pool. /// If zero will use the RAYON_NUM_THREADS environment variable. /// If RAYON_NUM_THREADS is invalid or zero will use the default.
num_threads: usize,
/// The thread we're building *from* will also be part of the pool.
use_current_thread: bool,
/// Custom closure, if any, to handle a panic that we cannot propagate /// anywhere else.
panic_handler: Option<Box<PanicHandler>>,
/// Closure to compute the name of a thread.
get_thread_name: Option<Box<dyn FnMut(usize) -> String>>,
/// The stack size for the created worker threads
stack_size: Option<usize>,
/// Closure invoked on worker thread start.
start_handler: Option<Box<StartHandler>>,
/// Closure invoked on worker thread exit.
exit_handler: Option<Box<ExitHandler>>,
/// Closure invoked to spawn threads.
spawn_handler: S,
/// If false, worker threads will execute spawned jobs in a /// "depth-first" fashion. If true, they will do a "breadth-first" /// fashion. Depth-first is the default.
breadth_first: bool,
}
/// Contains the rayon thread pool configuration. Use [`ThreadPoolBuilder`] instead. /// /// [`ThreadPoolBuilder`]: struct.ThreadPoolBuilder.html #[deprecated(note = "Use `ThreadPoolBuilder`")] #[derive(Default)] pubstruct Configuration {
builder: ThreadPoolBuilder,
}
/// The type for a panic handling closure. Note that this same closure /// may be invoked multiple times in parallel. type PanicHandler = dynFn(Box<dyn Any + Send>) + Send + Sync;
/// The type for a closure that gets invoked when a thread starts. The /// closure is passed the index of the thread on which it is invoked. /// Note that this same closure may be invoked multiple times in parallel. type StartHandler = dynFn(usize) + Send + Sync;
/// The type for a closure that gets invoked when a thread exits. The /// closure is passed the index of the thread on which is is invoked. /// Note that this same closure may be invoked multiple times in parallel. type ExitHandler = dynFn(usize) + Send + Sync;
// NB: We can't `#[derive(Default)]` because `S` is left ambiguous. impl Default for ThreadPoolBuilder { fn default() -> Self {
ThreadPoolBuilder {
num_threads: 0,
use_current_thread: false,
panic_handler: None,
get_thread_name: None,
stack_size: None,
start_handler: None,
exit_handler: None,
spawn_handler: DefaultSpawn,
breadth_first: false,
}
}
}
impl ThreadPoolBuilder { /// Creates and returns a valid rayon thread pool builder, but does not initialize it. pubfn new() -> Self { Self::default()
}
}
/// Note: the `S: ThreadSpawn` constraint is an internal implementation detail for the /// default spawn and those set by [`spawn_handler`](#method.spawn_handler). impl<S> ThreadPoolBuilder<S> where
S: ThreadSpawn,
{ /// Creates a new `ThreadPool` initialized using this configuration. pubfn build(self) -> Result<ThreadPool, ThreadPoolBuildError> {
ThreadPool::build(self)
}
/// Initializes the global thread pool. This initialization is /// **optional**. If you do not call this function, the thread pool /// will be automatically initialized with the default /// configuration. Calling `build_global` is not recommended, except /// in two scenarios: /// /// - You wish to change the default configuration. /// - You are running a benchmark, in which case initializing may /// yield slightly more consistent results, since the worker threads /// will already be ready to go even in the first iteration. But /// this cost is minimal. /// /// Initialization of the global thread pool happens exactly /// once. Once started, the configuration cannot be /// changed. Therefore, if you call `build_global` a second time, it /// will return an error. An `Ok` result indicates that this /// is the first initialization of the thread pool. pubfn build_global(self) -> Result<(), ThreadPoolBuildError> { let registry = registry::init_global_registry(self)?;
registry.wait_until_primed();
Ok(())
}
}
impl ThreadPoolBuilder { /// Creates a scoped `ThreadPool` initialized using this configuration. /// /// This is a convenience function for building a pool using [`std::thread::scope`] /// to spawn threads in a [`spawn_handler`](#method.spawn_handler). /// The threads in this pool will start by calling `wrapper`, which should /// do initialization and continue by calling `ThreadBuilder::run()`. /// /// [`std::thread::scope`]: https://doc.rust-lang.org/std/thread/fn.scope.html /// /// # Examples /// /// A scoped pool may be useful in combination with scoped thread-local variables. /// /// ``` /// # use rayon_core as rayon; /// /// scoped_tls::scoped_thread_local!(static POOL_DATA: Vec<i32>); /// /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// let pool_data = vec![1, 2, 3]; /// /// // We haven't assigned any TLS data yet. /// assert!(!POOL_DATA.is_set()); /// /// rayon::ThreadPoolBuilder::new() /// .build_scoped( /// // Borrow `pool_data` in TLS for each thread. /// |thread| POOL_DATA.set(&pool_data, || thread.run()), /// // Do some work that needs the TLS data. /// |pool| pool.install(|| assert!(POOL_DATA.is_set())), /// )?; /// /// // Once we've returned, `pool_data` is no longer borrowed. /// drop(pool_data); /// Ok(()) /// } /// ``` pubfn build_scoped<W, F, R>(self, wrapper: W, with_pool: F) -> Result<R, ThreadPoolBuildError> where
W: Fn(ThreadBuilder) + Sync, // expected to call `run()`
F: FnOnce(&ThreadPool) -> R,
{
std::thread::scope(|scope| { let pool = self
.spawn_handler(|thread| { letmut builder = std::thread::Builder::new(); iflet Some(name) = thread.name() {
builder = builder.name(name.to_string());
} iflet Some(size) = thread.stack_size() {
builder = builder.stack_size(size);
}
builder.spawn_scoped(scope, || wrapper(thread))?;
Ok(())
})
.build()?;
Ok(with_pool(&pool))
})
}
}
impl<S> ThreadPoolBuilder<S> { /// Sets a custom function for spawning threads. /// /// Note that the threads will not exit until after the pool is dropped. It /// is up to the caller to wait for thread termination if that is important /// for any invariants. For instance, threads created in [`std::thread::scope`] /// will be joined before that scope returns, and this will block indefinitely /// if the pool is leaked. Furthermore, the global thread pool doesn't terminate /// until the entire process exits! /// /// # Examples /// /// A minimal spawn handler just needs to call `run()` from an independent thread. /// /// ``` /// # use rayon_core as rayon; /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// let pool = rayon::ThreadPoolBuilder::new() /// .spawn_handler(|thread| { /// std::thread::spawn(|| thread.run()); /// Ok(()) /// }) /// .build()?; /// /// pool.install(|| println!("Hello from my custom thread!")); /// Ok(()) /// } /// ``` /// /// The default spawn handler sets the name and stack size if given, and propagates /// any errors from the thread builder. /// /// ``` /// # use rayon_core as rayon; /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// let pool = rayon::ThreadPoolBuilder::new() /// .spawn_handler(|thread| { /// let mut b = std::thread::Builder::new(); /// if let Some(name) = thread.name() { /// b = b.name(name.to_owned()); /// } /// if let Some(stack_size) = thread.stack_size() { /// b = b.stack_size(stack_size); /// } /// b.spawn(|| thread.run())?; /// Ok(()) /// }) /// .build()?; /// /// pool.install(|| println!("Hello from my fully custom thread!")); /// Ok(()) /// } /// ``` /// /// This can also be used for a pool of scoped threads like [`crossbeam::scope`], /// or [`std::thread::scope`] introduced in Rust 1.63, which is encapsulated in /// [`build_scoped`](#method.build_scoped). /// /// [`crossbeam::scope`]: https://docs.rs/crossbeam/0.8/crossbeam/fn.scope.html /// [`std::thread::scope`]: https://doc.rust-lang.org/std/thread/fn.scope.html /// /// ``` /// # use rayon_core as rayon; /// fn main() -> Result<(), rayon::ThreadPoolBuildError> { /// std::thread::scope(|scope| { /// let pool = rayon::ThreadPoolBuilder::new() /// .spawn_handler(|thread| { /// let mut builder = std::thread::Builder::new(); /// if let Some(name) = thread.name() { /// builder = builder.name(name.to_string()); /// } /// if let Some(size) = thread.stack_size() { /// builder = builder.stack_size(size); /// } /// builder.spawn_scoped(scope, || { /// // Add any scoped initialization here, then run! /// thread.run() /// })?; /// Ok(()) /// }) /// .build()?; /// /// pool.install(|| println!("Hello from my custom scoped thread!")); /// Ok(()) /// }) /// } /// ``` pubfn spawn_handler<F>(self, spawn: F) -> ThreadPoolBuilder<CustomSpawn<F>> where
F: FnMut(ThreadBuilder) -> io::Result<()>,
{
ThreadPoolBuilder {
spawn_handler: CustomSpawn::new(spawn), // ..self
num_threads: self.num_threads,
use_current_thread: self.use_current_thread,
panic_handler: self.panic_handler,
get_thread_name: self.get_thread_name,
stack_size: self.stack_size,
start_handler: self.start_handler,
exit_handler: self.exit_handler,
breadth_first: self.breadth_first,
}
}
/// Returns a reference to the current spawn handler. fn get_spawn_handler(&mutself) -> &mut S {
&mutself.spawn_handler
}
/// Get the number of threads that will be used for the thread /// pool. See `num_threads()` for more information. fn get_num_threads(&self) -> usize { ifself.num_threads > 0 { self.num_threads
} else { let default = || {
thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1)
};
// Support for deprecated `RAYON_RS_NUM_CPUS`. match env::var("RAYON_RS_NUM_CPUS")
.ok()
.and_then(|s| usize::from_str(&s).ok())
{
Some(x @ 1..) => x,
_ => default(),
}
}
}
/// Get the thread name for the thread with the given index. fn get_thread_name(&mutself, index: usize) -> Option<String> { let f = self.get_thread_name.as_mut()?;
Some(f(index))
}
/// Sets a closure which takes a thread index and returns /// the thread's name. pubfn thread_name<F>(mutself, closure: F) -> Self where
F: FnMut(usize) -> String + 'static,
{ self.get_thread_name = Some(Box::new(closure)); self
}
/// Sets the number of threads to be used in the rayon threadpool. /// /// If you specify a non-zero number of threads using this /// function, then the resulting thread-pools are guaranteed to /// start at most this number of threads. /// /// If `num_threads` is 0, or you do not call this function, then /// the Rayon runtime will select the number of threads /// automatically. At present, this is based on the /// `RAYON_NUM_THREADS` environment variable (if set), /// or the number of logical CPUs (otherwise). /// In the future, however, the default behavior may /// change to dynamically add or remove threads as needed. /// /// **Future compatibility warning:** Given the default behavior /// may change in the future, if you wish to rely on a fixed /// number of threads, you should use this function to specify /// that number. To reproduce the current default behavior, you /// may wish to use [`std::thread::available_parallelism`] /// to query the number of CPUs dynamically. /// /// **Old environment variable:** `RAYON_NUM_THREADS` is a one-to-one /// replacement of the now deprecated `RAYON_RS_NUM_CPUS` environment /// variable. If both variables are specified, `RAYON_NUM_THREADS` will /// be preferred. pubfn num_threads(mutself, num_threads: usize) -> Self { self.num_threads = num_threads; self
}
/// Use the current thread as one of the threads in the pool. /// /// The current thread is guaranteed to be at index 0, and since the thread is not managed by /// rayon, the spawn and exit handlers do not run for that thread. /// /// Note that the current thread won't run the main work-stealing loop, so jobs spawned into /// the thread-pool will generally not be picked up automatically by this thread unless you /// yield to rayon in some way, like via [`yield_now()`], [`yield_local()`], or [`scope()`]. /// /// # Local thread-pools /// /// Using this in a local thread-pool means the registry will be leaked. In future versions /// there might be a way of cleaning up the current-thread state. pubfn use_current_thread(mutself) -> Self { self.use_current_thread = true; self
}
/// Returns a copy of the current panic handler. fn take_panic_handler(&mutself) -> Option<Box<PanicHandler>> { self.panic_handler.take()
}
/// Normally, whenever Rayon catches a panic, it tries to /// propagate it to someplace sensible, to try and reflect the /// semantics of sequential execution. But in some cases, /// particularly with the `spawn()` APIs, there is no /// obvious place where we should propagate the panic to. /// In that case, this panic handler is invoked. /// /// If no panic handler is set, the default is to abort the /// process, under the principle that panics should not go /// unobserved. /// /// If the panic handler itself panics, this will abort the /// process. To prevent this, wrap the body of your panic handler /// in a call to `std::panic::catch_unwind()`. pubfn panic_handler<H>(mutself, panic_handler: H) -> Self where
H: Fn(Box<dyn Any + Send>) + Send + Sync + 'static,
{ self.panic_handler = Some(Box::new(panic_handler)); self
}
/// Get the stack size of the worker threads fn get_stack_size(&self) -> Option<usize> { self.stack_size
}
/// Sets the stack size of the worker threads pubfn stack_size(mutself, stack_size: usize) -> Self { self.stack_size = Some(stack_size); self
}
/// **(DEPRECATED)** Suggest to worker threads that they execute /// spawned jobs in a "breadth-first" fashion. /// /// Typically, when a worker thread is idle or blocked, it will /// attempt to execute the job from the *top* of its local deque of /// work (i.e., the job most recently spawned). If this flag is set /// to true, however, workers will prefer to execute in a /// *breadth-first* fashion -- that is, they will search for jobs at /// the *bottom* of their local deque. (At present, workers *always* /// steal from the bottom of other workers' deques, regardless of /// the setting of this flag.) /// /// If you think of the tasks as a tree, where a parent task /// spawns its children in the tree, then this flag loosely /// corresponds to doing a breadth-first traversal of the tree, /// whereas the default would be to do a depth-first traversal. /// /// **Note that this is an "execution hint".** Rayon's task /// execution is highly dynamic and the precise order in which /// independent tasks are executed is not intended to be /// guaranteed. /// /// This `breadth_first()` method is now deprecated per [RFC #1], /// and in the future its effect may be removed. Consider using /// [`scope_fifo()`] for a similar effect. /// /// [RFC #1]: https://github.com/rayon-rs/rfcs/blob/master/accepted/rfc0001-scope-scheduling.md /// [`scope_fifo()`]: fn.scope_fifo.html #[deprecated(note = "use `scope_fifo` and `spawn_fifo` for similar effect")] pubfn breadth_first(mutself) -> Self { self.breadth_first = true; self
}
/// Takes the current thread start callback, leaving `None`. fn take_start_handler(&mutself) -> Option<Box<StartHandler>> { self.start_handler.take()
}
/// Sets a callback to be invoked on thread start. /// /// The closure is passed the index of the thread on which it is invoked. /// Note that this same closure may be invoked multiple times in parallel. /// If this closure panics, the panic will be passed to the panic handler. /// If that handler returns, then startup will continue normally. pubfn start_handler<H>(mutself, start_handler: H) -> Self where
H: Fn(usize) + Send + Sync + 'static,
{ self.start_handler = Some(Box::new(start_handler)); self
}
/// Returns a current thread exit callback, leaving `None`. fn take_exit_handler(&mutself) -> Option<Box<ExitHandler>> { self.exit_handler.take()
}
/// Sets a callback to be invoked on thread exit. /// /// The closure is passed the index of the thread on which it is invoked. /// Note that this same closure may be invoked multiple times in parallel. /// If this closure panics, the panic will be passed to the panic handler. /// If that handler returns, then the thread will exit normally. pubfn exit_handler<H>(mutself, exit_handler: H) -> Self where
H: Fn(usize) + Send + Sync + 'static,
{ self.exit_handler = Some(Box::new(exit_handler)); self
}
}
#[allow(deprecated)] impl Configuration { /// Creates and return a valid rayon thread pool configuration, but does not initialize it. pubfn new() -> Configuration {
Configuration {
builder: ThreadPoolBuilder::new(),
}
}
/// Deprecated in favor of `ThreadPoolBuilder::build`. pubfn build(self) -> Result<ThreadPool, Box<dyn Error + 'static>> { self.builder.build().map_err(Box::from)
}
/// Deprecated in favor of `ThreadPoolBuilder::thread_name`. pubfn thread_name<F>(mutself, closure: F) -> Self where
F: FnMut(usize) -> String + 'static,
{ self.builder = self.builder.thread_name(closure); self
}
/// Deprecated in favor of `ThreadPoolBuilder::num_threads`. pubfn num_threads(mutself, num_threads: usize) -> Configuration { self.builder = self.builder.num_threads(num_threads); self
}
/// Deprecated in favor of `ThreadPoolBuilder::panic_handler`. pubfn panic_handler<H>(mutself, panic_handler: H) -> Configuration where
H: Fn(Box<dyn Any + Send>) + Send + Sync + 'static,
{ self.builder = self.builder.panic_handler(panic_handler); self
}
/// Deprecated in favor of `ThreadPoolBuilder::stack_size`. pubfn stack_size(mutself, stack_size: usize) -> Self { self.builder = self.builder.stack_size(stack_size); self
}
/// Deprecated in favor of `ThreadPoolBuilder::breadth_first`. pubfn breadth_first(mutself) -> Self { self.builder = self.builder.breadth_first(); self
}
/// Deprecated in favor of `ThreadPoolBuilder::start_handler`. pubfn start_handler<H>(mutself, start_handler: H) -> Configuration where
H: Fn(usize) + Send + Sync + 'static,
{ self.builder = self.builder.start_handler(start_handler); self
}
/// Deprecated in favor of `ThreadPoolBuilder::exit_handler`. pubfn exit_handler<H>(mutself, exit_handler: H) -> Configuration where
H: Fn(usize) + Send + Sync + 'static,
{ self.builder = self.builder.exit_handler(exit_handler); self
}
/// Returns a ThreadPoolBuilder with identical parameters. fn into_builder(self) -> ThreadPoolBuilder { self.builder
}
}
impl FnContext { /// Returns `true` if the closure was called from a different thread /// than it was provided from. #[inline] pubfn migrated(&self) -> bool { self.migrated
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.