|
4 | 4 | //! of spawned tasks and allows asynchronously awaiting the output of those
|
5 | 5 | //! tasks as they complete. See the documentation for the [`JoinSet`] type for
|
6 | 6 | //! details.
|
7 |
| -use std::fmt; |
8 | 7 | use std::future::Future;
|
9 | 8 | use std::pin::Pin;
|
10 | 9 | use std::task::{Context, Poll};
|
| 10 | +use std::{fmt, panic}; |
11 | 11 |
|
12 | 12 | use crate::runtime::Handle;
|
13 | 13 | #[cfg(tokio_unstable)]
|
@@ -374,6 +374,79 @@ impl<T: 'static> JoinSet<T> {
|
374 | 374 | while self.join_next().await.is_some() {}
|
375 | 375 | }
|
376 | 376 |
|
| 377 | + /// Awaits the completion of all tasks in this `JoinSet`, returning a vector of their results. |
| 378 | + /// |
| 379 | + /// The results will be stored in the order they completed not the order they were spawned. |
| 380 | + /// This is a convenience method that is equivalent to calling [`join_next`] in |
| 381 | + /// a loop. If any tasks on the `JoinSet` fail with an [`JoinError`], then this call |
| 382 | + /// to `join_all` will panic and all remaining tasks on the `JoinSet` are |
| 383 | + /// cancelled. To handle errors in any other way, manually call [`join_next`] |
| 384 | + /// in a loop. |
| 385 | + /// |
| 386 | + /// # Examples |
| 387 | + /// |
| 388 | + /// Spawn multiple tasks and `join_all` them. |
| 389 | + /// |
| 390 | + /// ``` |
| 391 | + /// use tokio::task::JoinSet; |
| 392 | + /// use std::time::Duration; |
| 393 | + /// |
| 394 | + /// #[tokio::main] |
| 395 | + /// async fn main() { |
| 396 | + /// let mut set = JoinSet::new(); |
| 397 | + /// |
| 398 | + /// for i in 0..3 { |
| 399 | + /// set.spawn(async move { |
| 400 | + /// tokio::time::sleep(Duration::from_secs(3 - i)).await; |
| 401 | + /// i |
| 402 | + /// }); |
| 403 | + /// } |
| 404 | + /// |
| 405 | + /// let output = set.join_all().await; |
| 406 | + /// assert_eq!(output, vec![2, 1, 0]); |
| 407 | + /// } |
| 408 | + /// ``` |
| 409 | + /// |
| 410 | + /// Equivalent implementation of `join_all`, using [`join_next`] and loop. |
| 411 | + /// |
| 412 | + /// ``` |
| 413 | + /// use tokio::task::JoinSet; |
| 414 | + /// use std::panic; |
| 415 | + /// |
| 416 | + /// #[tokio::main] |
| 417 | + /// async fn main() { |
| 418 | + /// let mut set = JoinSet::new(); |
| 419 | + /// |
| 420 | + /// for i in 0..3 { |
| 421 | + /// set.spawn(async move {i}); |
| 422 | + /// } |
| 423 | + /// |
| 424 | + /// let mut output = Vec::new(); |
| 425 | + /// while let Some(res) = set.join_next().await{ |
| 426 | + /// match res { |
| 427 | + /// Ok(t) => output.push(t), |
| 428 | + /// Err(err) if err.is_panic() => panic::resume_unwind(err.into_panic()), |
| 429 | + /// Err(err) => panic!("{err}"), |
| 430 | + /// } |
| 431 | + /// } |
| 432 | + /// assert_eq!(output.len(),3); |
| 433 | + /// } |
| 434 | + /// ``` |
| 435 | + /// [`join_next`]: fn@Self::join_next |
| 436 | + /// [`JoinError::id`]: fn@crate::task::JoinError::id |
| 437 | + pub async fn join_all(mut self) -> Vec<T> { |
| 438 | + let mut output = Vec::with_capacity(self.len()); |
| 439 | + |
| 440 | + while let Some(res) = self.join_next().await { |
| 441 | + match res { |
| 442 | + Ok(t) => output.push(t), |
| 443 | + Err(err) if err.is_panic() => panic::resume_unwind(err.into_panic()), |
| 444 | + Err(err) => panic!("{err}"), |
| 445 | + } |
| 446 | + } |
| 447 | + output |
| 448 | + } |
| 449 | + |
377 | 450 | /// Aborts all tasks on this `JoinSet`.
|
378 | 451 | ///
|
379 | 452 | /// This does not remove the tasks from the `JoinSet`. To wait for the tasks to complete
|
|
0 commit comments