pub struct RayonSafeOnce<T> { /* private fields */ }Expand description
Lazy-init cache safe to call from inside rayon par_iter.
std::sync::OnceLock::get_or_init parks racing threads on an OS
condition variable until the leader’s init closure finishes. If the
leader’s init closure itself dispatches a nested into_par_iter, the
parked threads are now unavailable as rayon workers, and the leader
blocks waiting for chunks that no one can service. Classic deadlock.
RayonSafeOnce removes the trap by computing the value outside any
lock. Concurrent racers may produce duplicate values; the first to
publish wins, the rest drop their result. No thread ever parks waiting
for another thread’s init to finish, so nested rayon par_iter inside
the init closure is safe.
Use this in place of OnceLock whenever the init closure transitively
runs rayon work and the cache may be entered concurrently from
inside another rayon par_iter. The redundant-work cost on first race
is the price for never deadlocking; in practice the loser threads
throw away one round of work and steady-state is identical to
OnceLock.
Implementations§
Source§impl<T> RayonSafeOnce<T>
impl<T> RayonSafeOnce<T>
pub const fn new() -> Self
Sourcepub fn get_or_compute<F>(&self, init: F) -> &Twhere
F: FnOnce() -> T,
pub fn get_or_compute<F>(&self, init: F) -> &Twhere
F: FnOnce() -> T,
Returns the cached value, computing it if absent.
The init closure runs WITHOUT holding any lock — calls from
concurrent rayon workers may all run it, and all but the first
to call set discard their result. This is the contract that
keeps nested into_par_iter inside init from deadlocking on
other workers parked on a OnceLock.
Named get_or_compute (not get_or_init) so the codebase-level
lint that bans OnceLock::get_or_init near rayon par_iter does
not flag this safe-by-construction path.
Trait Implementations§
Source§impl<T: Clone> Clone for RayonSafeOnce<T>
impl<T: Clone> Clone for RayonSafeOnce<T>
Source§impl<T: Debug> Debug for RayonSafeOnce<T>
impl<T: Debug> Debug for RayonSafeOnce<T>
Auto Trait Implementations§
impl<T> !Freeze for RayonSafeOnce<T>
impl<T> RefUnwindSafe for RayonSafeOnce<T>where
T: RefUnwindSafe + UnwindSafe,
impl<T> Send for RayonSafeOnce<T>where
T: Send,
impl<T> Sync for RayonSafeOnce<T>
impl<T> Unpin for RayonSafeOnce<T>where
T: Unpin,
impl<T> UnsafeUnpin for RayonSafeOnce<T>where
T: UnsafeUnpin,
impl<T> UnwindSafe for RayonSafeOnce<T>where
T: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more