pub fn join<A, B, RA, RB>(&self, oper_a: A, oper_b: B) -> (RA, RB)
    where
        A: FnOnce() -> RA + Send,
        B: FnOnce() -> RB + Send,
        RA: Send,
        RB: Send,
    {
        #[inline]
        fn call<R>(f: impl FnOnce() -> R) -> impl FnOnce(FnContext) -> R { move |_| f() }

        self.join_context(call(oper_a), call(oper_b))
    }
/// Takes two closures and *potentially* runs them in parallel. It
/// returns a pair of the results from those closures.
///
/// Conceptually, calling `join()` is similar to spawning two threads,
/// one executing each of the two closures. However, the
/// implementation is quite different and incurs very low
/// overhead. The underlying technique is called "work stealing": the
/// Rayon runtime uses a fixed pool of worker threads and attempts to
/// only execute code in parallel when there are idle CPUs to handle
/// it.
///
/// When `join` is called from outside the thread pool, the calling
/// thread will block while the closures execute in the pool.  When
/// `join` is called within the pool, the calling thread still actively
/// participates in the thread pool. It will begin by executing closure
/// A (on the current thread). While it is doing that, it will advertise
/// closure B as being available for other threads to execute. Once closure A
/// has completed, the current thread will try to execute closure B;
/// if however closure B has been stolen, then it will look for other work
/// while waiting for the thief to fully execute closure B. (This is the
/// typical work-stealing strategy).
///
/// # Warning about blocking I/O
///
/// The assumption is that the closures given to `join()` are
/// CPU-bound tasks that do not perform I/O or other blocking
/// operations. If you do perform I/O, and that I/O should block
/// (e.g., waiting for a network request), the overall performance may
/// be poor.  Moreover, if you cause one closure to be blocked waiting
/// on another (for example, using a channel), that could lead to a
/// deadlock.
///
/// # Panics
///
/// No matter what happens, both closures will always be executed.  If
/// a single closure panics, whether it be the first or second
/// closure, that panic will be propagated and hence `join()` will
/// panic with the same panic value. If both closures panic, `join()`
/// will panic with the panic value from the first closure.
Takes two closures and *potentially* runs them in parallel. It
returns a pair of the results from those closures.

Conceptually, calling `join()` is similar to spawning two threads,
one executing each of the two closures. However, the
implementation is quite different and incurs very low
overhead. The underlying technique is called "work stealing": the
Rayon runtime uses a fixed pool of worker threads and attempts to
only execute code in parallel when there are idle CPUs to handle
it.

When `join` is called from outside the thread pool, the calling
thread will block while the closures execute in the pool.  When
`join` is called within the pool, the calling thread still actively
participates in the thread pool. It will begin by executing closure
A (on the current thread). While it is doing that, it will advertise
closure B as being available for other threads to execute. Once closure A
has completed, the current thread will try to execute closure B;
if however closure B has been stolen, then it will look for other work
while waiting for the thief to fully execute closure B. (This is the
typical work-stealing strategy).
Takes two closures and * potentially * runs them in parallel . It returns a pair of the results from those closures . Conceptually calling ` join () ` is similar to spawning two threads one executing each of the two closures . However the implementation is quite different and incurs very low overhead . The underlying technique is called " work stealing " : the Rayon runtime uses a fixed pool of worker threads and attempts to only execute code in parallel when there are idle CPUs to handle it . When ` join ` is called from outside the thread pool the calling thread will block while the closures execute in the pool . When ` join ` is called within the pool the calling thread still actively participates in the thread pool . It will begin by executing closure A ( on the current thread ) . While it is doing that it will advertise closure B as being available for other threads to execute . Once closure A has completed the current thread will try to execute closure B ; if however closure B has been stolen then it will look for other work while waiting for the thief to fully execute closure B . ( This is the typical work - stealing strategy ) .
pub fn join<A, B, RA, RB>(&self, oper_a: A, oper_b: B) -> (RA, RB)
    where
        A: FnOnce() -> RA + Send,
        B: FnOnce() -> RB + Send,
        RA: Send,
        RB: Send,
    {
        #[inline]
        fn call<R>(f: impl FnOnce() -> R) -> impl FnOnce(FnContext) -> R { move |_| f() }
        self.join_context(call(oper_a), call(oper_b))
    }
pub fn join < A , B , RA , RB > ( & self , oper_a : A , oper_b : B ) -> ( RA , RB ) where A : FnOnce ( ) -> RA + Send , B : FnOnce ( ) -> RB + Send , RA : Send , RB : Send , { # [ inline ] fn call < R > ( f : impl FnOnce ( ) -> R ) -> impl FnOnce ( FnContext ) -> R { move | _ | f ( ) } self . join_context ( call ( oper_a ) , call ( oper_b ) ) }
Takes two closures and *potentially* runs them in parallel.
Takes two closures and * potentially * runs them in parallel .
&self
oper_a
A
oper_b
B
&self
oper_a
A
oper_b
B
warning about blocking i/o
The assumption is that the closures given to `join()` are
CPU-bound tasks that do not perform I/O or other blocking
operations. If you do perform I/O, and that I/O should block
, the overall performance may
be poor.  Moreover, if you cause one closure to be blocked waiting
on another (for example, using a channel), that could lead to a
deadlock.
The assumption is that the closures given to ` join () ` are CPU - bound tasks that do not perform I / O or other blocking operations . If you do perform I / O and that I / O should block the overall performance may be poor . Moreover if you cause one closure to be blocked waiting on another ( for example using a channel ) that could lead to a deadlock .
panics
No matter what happens, both closures will always be executed.  If
a single closure panics, whether it be the first or second
closure, that panic will be propagated and hence `join()` will
panic with the same panic value. If both closures panic, `join()`
will panic with the panic value from the first closure.
No matter what happens both closures will always be executed . If a single closure panics whether it be the first or second closure that panic will be propagated and hence ` join () ` will panic with the same panic value . If both closures panic ` join () ` will panic with the panic value from the first closure .