macro_rules! doc {
($join:item) => { /// Waits on multiple concurrent branches, returning when **all** branches /// complete. /// /// The `join!` macro must be used inside of async functions, closures, and /// blocks. /// /// The `join!` macro takes a list of async expressions and evaluates them /// concurrently on the same task. Each async expression evaluates to a future /// and the futures from each expression are multiplexed on the current task. /// /// When working with async expressions returning `Result`, `join!` will wait /// for **all** branches complete regardless if any complete with `Err`. Use /// [`try_join!`] to return early when `Err` is encountered. /// /// [`try_join!`]: crate::try_join /// /// # Notes /// /// The supplied futures are stored inline and do not require allocating a /// `Vec`. /// /// ## Runtime characteristics /// /// By running all async expressions on the current task, the expressions are /// able to run **concurrently** but not in **parallel**. This means all /// expressions are run on the same thread and if one branch blocks the thread, /// all other expressions will be unable to continue. If parallelism is /// required, spawn each async expression using [`tokio::spawn`] and pass the /// join handle to `join!`. /// /// [`tokio::spawn`]: crate::spawn /// /// ## Fairness /// /// By default, `join!`'s generated future rotates which contained /// future is polled first whenever it is woken. /// /// This behavior can be overridden by adding `biased;` to the beginning of the /// macro usage. See the examples for details. This will cause `join` to poll /// the futures in the order they appear from top to bottom. /// /// You may want this if your futures may interact in a way where known polling order is significant. /// /// But there is an important caveat to this mode. It becomes your responsibility /// to ensure that the polling order of your futures is fair. If for example you /// are joining a stream and a shutdown future, and the stream has a /// huge volume of messages that takes a long time to finish processing per poll, you should /// place the shutdown future earlier in the `join!` list to ensure that it is /// always polled, and will not be delayed due to the stream future taking a long time to return /// `Poll::Pending`. /// /// # Examples /// /// Basic join with two branches /// /// ``` /// async fn do_stuff_async() { /// // async work /// } /// /// async fn more_async_work() { /// // more here /// } /// /// # #[tokio::main(flavor = "current_thread")] /// # async fn main() { /// let (first, second) = tokio::join!( /// do_stuff_async(), /// more_async_work()); /// /// // do something with the values /// # } /// ``` /// /// Using the `biased;` mode to control polling order. /// /// ``` /// # #[cfg(not(target_family = "wasm"))] /// # { /// async fn do_stuff_async() { /// // async work /// } /// /// async fn more_async_work() { /// // more here /// } /// /// # #[tokio::main(flavor = "current_thread")] /// # async fn main() { /// let (first, second) = tokio::join!( /// biased; /// do_stuff_async(), /// more_async_work() /// ); /// /// // do something with the values /// # } /// # } /// ```
#[cfg(not(doc))]
doc! {macro_rules! join {
(@ { // Type of rotator that controls which inner future to start with // when polling our output future.
rotator_select=$rotator_select:ty;
// One `_` for each branch in the `join!` macro. This is not used once // normalization is complete.
( $($count:tt)* )
// The expression `0+1+1+ ... +1` equal to the number of branches.
( $($total:tt)* )
}) => {{ // Safety: nothing must be moved out of `futures`. This is to satisfy // the requirement of `Pin::new_unchecked` called below. // // We can't use the `pin!` macro for this because `futures` is a tuple // and the standard library provides no way to pin-project to the fields // of a tuple. letmut futures = ( $( $crate::macros::support::maybe_done($e), )* );
// Each time the future created by poll_fn is polled, if not using biased mode, // a different future is polled first to ensure every future passed to join! // can make progress even if one of the futures consumes the whole budget. letmut rotator = <$rotator_select as $crate::macros::support::RotatorSelect>::Rotator::<{$($total)*}>::default();
// The number of futures that will be skipped in the first loop iteration. letmut skip = rotator.num_skip();
// This loop runs twice and the first `skip` futures // are not polled in the first iteration. loop {
$( if skip == 0 { if to_run == 0 { // Every future has been polled break;
}
to_run -= 1;
// Extract the future for this branch from the tuple. let ( $($skip,)* fut, .. ) = &mut *futures;
// Safety: future is stored on the stack above // and never moved. letmut fut = unsafe { $crate::macros::support::Pin::new_unchecked(fut) };
// Try polling if $crate::macros::support::Future::poll(fut.as_mut(), cx).is_pending() {
is_pending = true;
}
} else { // Future skipped, one less future to skip in the next iteration
skip -= 1;
}
)*
}
if is_pending {
$crate::macros::support::Poll::Pending
} else {
$crate::macros::support::Poll::Ready(($({ // Extract the future for this branch from the tuple. let ( $($skip,)* fut, .. ) = &mut futures;
// Safety: future is stored on the stack above // and never moved. letmut fut = unsafe { $crate::macros::support::Pin::new_unchecked(fut) };
/// Helper trait to select which type of `Rotator` to use. // We need this to allow specifying a const generic without // colliding with caller const names due to macro hygiene. pubtrait RotatorSelect { type Rotator<const COUNT: u32>: Default;
}
/// Marker type indicating that the starting branch should /// rotate each poll. #[derive(Debug)] pubstruct SelectNormal; /// Marker type indicating that the starting branch should /// be the first declared branch each poll. #[derive(Debug)] pubstruct SelectBiased;
impl RotatorSelect for SelectNormal { type Rotator<const COUNT: u32> = Rotator<COUNT>;
}
impl RotatorSelect for SelectBiased { type Rotator<const COUNT: u32> = BiasedRotator;
}
/// Rotates by one each [`Self::num_skip`] call up to COUNT - 1. #[derive(Default, Debug)] pubstruct Rotator<const COUNT: u32> {
next: u32,
}
impl<const COUNT: u32> Rotator<COUNT> { /// Rotates by one each [`Self::num_skip`] call up to COUNT - 1 #[inline] pubfn num_skip(&mutself) -> u32 { let num_skip = self.next; self.next += 1; ifself.next == COUNT { self.next = 0;
}
num_skip
}
}
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.