diff --git a/benches/benches/bevy_tasks/iter.rs b/benches/benches/bevy_tasks/iter.rs index aafa4b6f5b3db..5f267dbc4b4e0 100644 --- a/benches/benches/bevy_tasks/iter.rs +++ b/benches/benches/bevy_tasks/iter.rs @@ -6,8 +6,6 @@ impl<'a, T> ParallelIterator> for ParChunks<'a, T> where T: 'a + Send + Sync, { - type Item = &'a T; - fn next_batch(&mut self) -> Option> { self.0.next().map(|s| s.iter()) } @@ -18,8 +16,6 @@ impl<'a, T> ParallelIterator> for ParChunksMut<'a, T> where T: 'a + Send + Sync, { - type Item = &'a mut T; - fn next_batch(&mut self) -> Option> { self.0.next().map(|s| s.iter_mut()) } diff --git a/crates/bevy_tasks/src/iter/adapters.rs b/crates/bevy_tasks/src/iter/adapters.rs index 047f6fb8ad5f0..d05da201ad25d 100644 --- a/crates/bevy_tasks/src/iter/adapters.rs +++ b/crates/bevy_tasks/src/iter/adapters.rs @@ -10,11 +10,9 @@ pub struct Chain { impl ParallelIterator for Chain where B: Iterator + Send, - T: ParallelIterator, - U: ParallelIterator, + T: ParallelIterator, + U: ParallelIterator, { - type Item = T::Item; - fn next_batch(&mut self) -> Option { if self.left_in_progress { match self.left.next_batch() { @@ -35,11 +33,9 @@ pub struct Map { impl ParallelIterator> for Map where B: Iterator + Send, - U: ParallelIterator, - F: FnMut(U::Item) -> T + Send + Clone, + U: ParallelIterator, + F: FnMut(B::Item) -> T + Send + Clone, { - type Item = T; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.map(self.f.clone())) } @@ -54,11 +50,9 @@ pub struct Filter { impl ParallelIterator> for Filter where B: Iterator + Send, - P: ParallelIterator, - F: FnMut(&P::Item) -> bool + Send + Clone, + P: ParallelIterator, + F: FnMut(&B::Item) -> bool + Send + Clone, { - type Item = P::Item; - fn next_batch(&mut self) -> Option> { self.iter .next_batch() @@ -75,11 +69,9 @@ pub struct FilterMap { impl ParallelIterator> for FilterMap where B: Iterator + Send, - P: ParallelIterator, - F: FnMut(P::Item) -> Option + Send + Clone, + P: ParallelIterator, + F: FnMut(B::Item) -> Option + Send + Clone, { - type Item = R; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.filter_map(self.f.clone())) } @@ -94,13 +86,11 @@ pub struct FlatMap { impl ParallelIterator> for FlatMap where B: Iterator + Send, - P: ParallelIterator, - F: FnMut(P::Item) -> U + Send + Clone, + P: ParallelIterator, + F: FnMut(B::Item) -> U + Send + Clone, U: IntoIterator, U::IntoIter: Send, { - type Item = U::Item; - // This extends each batch using the flat map. The other option is // to turn each IntoIter into its own batch. fn next_batch(&mut self) -> Option> { @@ -116,12 +106,10 @@ pub struct Flatten

{ impl ParallelIterator> for Flatten

where B: Iterator + Send, - P: ParallelIterator, + P: ParallelIterator, B::Item: IntoIterator, ::IntoIter: Send, { - type Item = ::Item; - // This extends each batch using the flatten. The other option is to // turn each IntoIter into its own batch. fn next_batch(&mut self) -> Option> { @@ -137,10 +125,8 @@ pub struct Fuse

{ impl ParallelIterator for Fuse

where B: Iterator + Send, - P: ParallelIterator, + P: ParallelIterator, { - type Item = P::Item; - fn next_batch(&mut self) -> Option { match &mut self.iter { Some(iter) => match iter.next_batch() { @@ -164,11 +150,9 @@ pub struct Inspect { impl ParallelIterator> for Inspect where B: Iterator + Send, - P: ParallelIterator, - F: FnMut(&P::Item) + Send + Clone, + P: ParallelIterator, + F: FnMut(&B::Item) + Send + Clone, { - type Item = P::Item; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.inspect(self.f.clone())) } @@ -182,11 +166,9 @@ pub struct Copied

{ impl<'a, B, P, T> ParallelIterator> for Copied

where B: Iterator + Send, - P: ParallelIterator, + P: ParallelIterator, T: 'a + Copy, { - type Item = T; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.copied()) } @@ -200,11 +182,9 @@ pub struct Cloned

{ impl<'a, B, P, T> ParallelIterator> for Cloned

where B: Iterator + Send, - P: ParallelIterator, + P: ParallelIterator, T: 'a + Copy, { - type Item = T; - fn next_batch(&mut self) -> Option> { self.iter.next_batch().map(|b| b.cloned()) } @@ -219,10 +199,8 @@ pub struct Cycle

{ impl ParallelIterator for Cycle

where B: Iterator + Send, - P: ParallelIterator + Clone, + P: ParallelIterator + Clone, { - type Item = P::Item; - fn next_batch(&mut self) -> Option { match self.curr.as_mut().and_then(|c| c.next_batch()) { batch @ Some(_) => batch, diff --git a/crates/bevy_tasks/src/iter/mod.rs b/crates/bevy_tasks/src/iter/mod.rs index bebc1c0792e2c..02f6cd8528195 100644 --- a/crates/bevy_tasks/src/iter/mod.rs +++ b/crates/bevy_tasks/src/iter/mod.rs @@ -11,18 +11,16 @@ pub use adapters::*; /// run in parallel is inexpensive, *a [`ParallelIterator`] could take longer /// than a normal [`Iterator`]*. Therefore, you should profile your code before /// using [`ParallelIterator`]. -pub trait ParallelIterator +pub trait ParallelIterator where - B: Iterator + Send, + BatchIter: Iterator + Send, Self: Sized + Send, { - type Item; - /// Returns the next batch of items for processing. /// /// Each batch is an iterator with items of the same type as the /// [`ParallelIterator`]. Returns `None` when there are no batches left. - fn next_batch(&mut self) -> Option; + fn next_batch(&mut self) -> Option; /// Returns the bounds on the remaining number of items in the /// parallel iterator. @@ -48,7 +46,7 @@ where /// Consumes the parallel iterator and returns the last item. /// /// See [`Iterator::last()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.last) - fn last(mut self, _pool: &TaskPool) -> Option { + fn last(mut self, _pool: &TaskPool) -> Option { let mut last_item = None; while let Some(batch) = self.next_batch() { last_item = batch.last(); @@ -60,7 +58,7 @@ where /// /// See [`Iterator::nth()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.nth) // TODO: Optimize with size_hint on each batch - fn nth(mut self, _pool: &TaskPool, n: usize) -> Option { + fn nth(mut self, _pool: &TaskPool, n: usize) -> Option { let mut i = 0; while let Some(batch) = self.next_batch() { for item in batch { @@ -80,7 +78,7 @@ where // TODO: Use IntoParallelIterator for U fn chain(self, other: U) -> Chain where - U: ParallelIterator, + U: ParallelIterator, { Chain { left: self, @@ -95,7 +93,7 @@ where /// See [`Iterator::map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.map) fn map(self, f: F) -> Map where - F: FnMut(Self::Item) -> T + Send + Clone, + F: FnMut(BatchIter::Item) -> T + Send + Clone, { Map { iter: self, f } } @@ -105,7 +103,7 @@ where /// See [`Iterator::for_each()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.for_each) fn for_each(mut self, pool: &TaskPool, f: F) where - F: FnMut(Self::Item) + Send + Clone + Sync, + F: FnMut(BatchIter::Item) + Send + Clone + Sync, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -123,7 +121,7 @@ where /// See [`Iterator::filter()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter) fn filter(self, predicate: F) -> Filter where - F: FnMut(&Self::Item) -> bool, + F: FnMut(&BatchIter::Item) -> bool, { Filter { iter: self, @@ -136,7 +134,7 @@ where /// See [`Iterator::filter_map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.filter_map) fn filter_map(self, f: F) -> FilterMap where - F: FnMut(Self::Item) -> Option, + F: FnMut(BatchIter::Item) -> Option, { FilterMap { iter: self, f } } @@ -147,7 +145,7 @@ where /// See [`Iterator::flat_map()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flat_map) fn flat_map(self, f: F) -> FlatMap where - F: FnMut(Self::Item) -> U, + F: FnMut(BatchIter::Item) -> U, U: IntoIterator, { FlatMap { iter: self, f } @@ -158,7 +156,7 @@ where /// See [`Iterator::flatten()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.flatten) fn flatten(self) -> Flatten where - Self::Item: IntoIterator, + BatchIter::Item: IntoIterator, { Flatten { iter: self } } @@ -176,7 +174,7 @@ where /// See [`Iterator::inspect()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.inspect) fn inspect(self, f: F) -> Inspect where - F: FnMut(&Self::Item), + F: FnMut(&BatchIter::Item), { Inspect { iter: self, f } } @@ -194,8 +192,8 @@ where // TODO: Investigate optimizations for less copying fn collect(mut self, pool: &TaskPool) -> C where - C: std::iter::FromIterator, - Self::Item: Send + 'static, + C: std::iter::FromIterator, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -213,9 +211,9 @@ where // TODO: Investigate optimizations for less copying fn partition(mut self, pool: &TaskPool, f: F) -> (C, C) where - C: Default + Extend + Send, - F: FnMut(&Self::Item) -> bool + Send + Sync + Clone, - Self::Item: Send + 'static, + C: Default + Extend + Send, + F: FnMut(&BatchIter::Item) -> bool + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { let (mut a, mut b) = <(C, C)>::default(); pool.scope(|s| { @@ -241,7 +239,7 @@ where /// See [`Iterator::fold()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.fold) fn fold(mut self, pool: &TaskPool, init: C, f: F) -> Vec where - F: FnMut(C, Self::Item) -> C + Send + Sync + Clone, + F: FnMut(C, BatchIter::Item) -> C + Send + Sync + Clone, C: Clone + Send + Sync + 'static, { pool.scope(|s| { @@ -260,7 +258,7 @@ where /// See [`Iterator::all()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.all) fn all(mut self, pool: &TaskPool, f: F) -> bool where - F: FnMut(Self::Item) -> bool + Send + Sync + Clone, + F: FnMut(BatchIter::Item) -> bool + Send + Sync + Clone, { pool.scope(|s| { while let Some(mut batch) = self.next_batch() { @@ -279,7 +277,7 @@ where /// See [`Iterator::any()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.any) fn any(mut self, pool: &TaskPool, f: F) -> bool where - F: FnMut(Self::Item) -> bool + Send + Sync + Clone, + F: FnMut(BatchIter::Item) -> bool + Send + Sync + Clone, { pool.scope(|s| { while let Some(mut batch) = self.next_batch() { @@ -299,7 +297,7 @@ where // TODO: Investigate optimizations for less copying fn position(mut self, pool: &TaskPool, f: F) -> Option where - F: FnMut(Self::Item) -> bool + Send + Sync + Clone, + F: FnMut(BatchIter::Item) -> bool + Send + Sync + Clone, { let poses = pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -330,9 +328,9 @@ where /// Returns the maximum item of a parallel iterator. /// /// See [`Iterator::max()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max) - fn max(mut self, pool: &TaskPool) -> Option + fn max(mut self, pool: &TaskPool) -> Option where - Self::Item: Ord + Send + 'static, + BatchIter::Item: Ord + Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -347,9 +345,9 @@ where /// Returns the minimum item of a parallel iterator. /// /// See [`Iterator::min()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min) - fn min(mut self, pool: &TaskPool) -> Option + fn min(mut self, pool: &TaskPool) -> Option where - Self::Item: Ord + Send + 'static, + BatchIter::Item: Ord + Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -364,11 +362,11 @@ where /// Returns the item that gives the maximum value from the specified function. /// /// See [`Iterator::max_by_key()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by_key) - fn max_by_key(mut self, pool: &TaskPool, f: F) -> Option + fn max_by_key(mut self, pool: &TaskPool, f: F) -> Option where R: Ord, - F: FnMut(&Self::Item) -> R + Send + Sync + Clone, - Self::Item: Send + 'static, + F: FnMut(&BatchIter::Item) -> R + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -385,10 +383,10 @@ where /// function. /// /// See [`Iterator::max_by()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by) - fn max_by(mut self, pool: &TaskPool, f: F) -> Option + fn max_by(mut self, pool: &TaskPool, f: F) -> Option where - F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering + Send + Sync + Clone, - Self::Item: Send + 'static, + F: FnMut(&BatchIter::Item, &BatchIter::Item) -> std::cmp::Ordering + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -404,11 +402,11 @@ where /// Returns the item that gives the minimum value from the specified function. /// /// See [`Iterator::min_by_key()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by_key) - fn min_by_key(mut self, pool: &TaskPool, f: F) -> Option + fn min_by_key(mut self, pool: &TaskPool, f: F) -> Option where R: Ord, - F: FnMut(&Self::Item) -> R + Send + Sync + Clone, - Self::Item: Send + 'static, + F: FnMut(&BatchIter::Item) -> R + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -425,10 +423,10 @@ where /// function. /// /// See [`Iterator::min_by()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by) - fn min_by(mut self, pool: &TaskPool, f: F) -> Option + fn min_by(mut self, pool: &TaskPool, f: F) -> Option where - F: FnMut(&Self::Item, &Self::Item) -> std::cmp::Ordering + Send + Sync + Clone, - Self::Item: Send + 'static, + F: FnMut(&BatchIter::Item, &BatchIter::Item) -> std::cmp::Ordering + Send + Sync + Clone, + BatchIter::Item: Send + 'static, { pool.scope(|s| { while let Some(batch) = self.next_batch() { @@ -446,7 +444,7 @@ where /// See [`Iterator::copied()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.copied) fn copied<'a, T>(self) -> Copied where - Self: ParallelIterator, + Self: ParallelIterator, T: 'a + Copy, { Copied { iter: self } @@ -457,7 +455,7 @@ where /// See [`Iterator::cloned()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.cloned) fn cloned<'a, T>(self) -> Cloned where - Self: ParallelIterator, + Self: ParallelIterator, T: 'a + Copy, { Cloned { iter: self } @@ -481,7 +479,7 @@ where /// See [`Iterator::sum()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum) fn sum(mut self, pool: &TaskPool) -> R where - S: std::iter::Sum + Send + 'static, + S: std::iter::Sum + Send + 'static, R: std::iter::Sum, { pool.scope(|s| { @@ -498,7 +496,7 @@ where /// See [`Iterator::product()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.product) fn product(mut self, pool: &TaskPool) -> R where - S: std::iter::Product + Send + 'static, + S: std::iter::Product + Send + 'static, R: std::iter::Product, { pool.scope(|s| { diff --git a/crates/bevy_tasks/src/lib.rs b/crates/bevy_tasks/src/lib.rs index db95dc28db447..d4e8d9dfe1367 100644 --- a/crates/bevy_tasks/src/lib.rs +++ b/crates/bevy_tasks/src/lib.rs @@ -1,3 +1,4 @@ +#![warn(missing_docs)] #![doc = include_str!("../README.md")] mod slice; @@ -25,6 +26,7 @@ pub use countdown_event::CountdownEvent; mod iter; pub use iter::ParallelIterator; +#[allow(missing_docs)] pub mod prelude { #[doc(hidden)] pub use crate::{ @@ -34,10 +36,5 @@ pub mod prelude { }; } -pub fn logical_core_count() -> usize { - num_cpus::get() -} - -pub fn physical_core_count() -> usize { - num_cpus::get_physical() -} +pub use num_cpus::get as logical_core_count; +pub use num_cpus::get_physical as physical_core_count; diff --git a/crates/bevy_tasks/src/slice.rs b/crates/bevy_tasks/src/slice.rs index a04c9af10a28f..4b5d875ea989b 100644 --- a/crates/bevy_tasks/src/slice.rs +++ b/crates/bevy_tasks/src/slice.rs @@ -1,6 +1,35 @@ use super::TaskPool; +/// Provides functions for mapping read-only slices across a provided [`TaskPool`]. pub trait ParallelSlice: AsRef<[T]> { + /// Splits the slice in chunks of size `chunks_size` or less and maps the chunks + /// in parallel across the provided `task_pool`. One task is spawned in the task pool + /// for every chunk. + /// + /// Returns a `Vec` of the mapped results in the same order as the input. + /// + /// # Example + /// + /// ```rust + /// # use bevy_tasks::prelude::*; + /// # use bevy_tasks::TaskPool; + /// let task_pool = TaskPool::new(); + /// let counts = (0..10000).collect::>(); + /// let incremented = counts.par_chunk_map(&task_pool, 100, |chunk| { + /// let mut results = Vec::new(); + /// for count in chunk { + /// results.push(*count + 2); + /// } + /// results + /// }); + /// # let flattened: Vec<_> = incremented.into_iter().flatten().collect(); + /// # assert_eq!(flattened, (2..10002).collect::>()); + /// ``` + /// + /// # See Also + /// + /// - [`ParallelSliceMut::par_chunk_map_mut`] for mapping mutable slices. + /// - [`ParallelSlice::par_splat_map`] for mapping when a specific chunk size is unknown. fn par_chunk_map(&self, task_pool: &TaskPool, chunk_size: usize, f: F) -> Vec where F: Fn(&[T]) -> R + Send + Sync, @@ -15,6 +44,36 @@ pub trait ParallelSlice: AsRef<[T]> { }) } + /// Splits the slice into a maximum of `max_tasks` chunks, and maps the chunks in parallel + /// across the provided `task_pool`. One task is spawned in the task pool for every chunk. + /// + /// If `max_tasks` is `None`, this function will attempt to use one chunk per thread in + /// `task_pool`. + /// + /// Returns a `Vec` of the mapped results in the same order as the input. + /// + /// # Example + /// + /// ```rust + /// # use bevy_tasks::prelude::*; + /// # use bevy_tasks::TaskPool; + /// let task_pool = TaskPool::new(); + /// let counts = (0..10000).collect::>(); + /// let incremented = counts.par_splat_map(&task_pool, None, |chunk| { + /// let mut results = Vec::new(); + /// for count in chunk { + /// results.push(*count + 2); + /// } + /// results + /// }); + /// # let flattened: Vec<_> = incremented.into_iter().flatten().collect(); + /// # assert_eq!(flattened, (2..10002).collect::>()); + /// ``` + /// + /// # See Also + /// + /// [`ParallelSliceMut::par_splat_map_mut`] for mapping mutable slices. + /// [`ParallelSlice::par_chunk_map`] for mapping when a specific chunk size is desirable. fn par_splat_map(&self, task_pool: &TaskPool, max_tasks: Option, f: F) -> Vec where F: Fn(&[T]) -> R + Send + Sync, @@ -35,7 +94,39 @@ pub trait ParallelSlice: AsRef<[T]> { impl ParallelSlice for S where S: AsRef<[T]> {} +/// Provides functions for mapping mutable slices across a provided [`TaskPool`]. pub trait ParallelSliceMut: AsMut<[T]> { + /// Splits the slice in chunks of size `chunks_size` or less and maps the chunks + /// in parallel across the provided `task_pool`. One task is spawned in the task pool + /// for every chunk. + /// + /// Returns a `Vec` of the mapped results in the same order as the input. + /// + /// # Example + /// + /// ```rust + /// # use bevy_tasks::prelude::*; + /// # use bevy_tasks::TaskPool; + /// let task_pool = TaskPool::new(); + /// let mut counts = (0..10000).collect::>(); + /// let incremented = counts.par_chunk_map_mut(&task_pool, 100, |chunk| { + /// let mut results = Vec::new(); + /// for count in chunk { + /// *count += 5; + /// results.push(*count - 2); + /// } + /// results + /// }); + /// + /// assert_eq!(counts, (5..10005).collect::>()); + /// # let flattened: Vec<_> = incremented.into_iter().flatten().collect(); + /// # assert_eq!(flattened, (3..10003).collect::>()); + /// ``` + /// + /// # See Also + /// + /// [`ParallelSlice::par_chunk_map`] for mapping immutable slices. + /// [`ParallelSliceMut::par_splat_map_mut`] for mapping when a specific chunk size is unknown. fn par_chunk_map_mut(&mut self, task_pool: &TaskPool, chunk_size: usize, f: F) -> Vec where F: Fn(&mut [T]) -> R + Send + Sync, @@ -50,6 +141,39 @@ pub trait ParallelSliceMut: AsMut<[T]> { }) } + /// Splits the slice into a maximum of `max_tasks` chunks, and maps the chunks in parallel + /// across the provided `task_pool`. One task is spawned in the task pool for every chunk. + /// + /// If `max_tasks` is `None`, this function will attempt to use one chunk per thread in + /// `task_pool`. + /// + /// Returns a `Vec` of the mapped results in the same order as the input. + /// + /// # Example + /// + /// ```rust + /// # use bevy_tasks::prelude::*; + /// # use bevy_tasks::TaskPool; + /// let task_pool = TaskPool::new(); + /// let mut counts = (0..10000).collect::>(); + /// let incremented = counts.par_splat_map_mut(&task_pool, None, |chunk| { + /// let mut results = Vec::new(); + /// for count in chunk { + /// *count += 5; + /// results.push(*count - 2); + /// } + /// results + /// }); + /// + /// assert_eq!(counts, (5..10005).collect::>()); + /// # let flattened: Vec<_> = incremented.into_iter().flatten().collect::>(); + /// # assert_eq!(flattened, (3..10003).collect::>()); + /// ``` + /// + /// # See Also + /// + /// [`ParallelSlice::par_splat_map`] for mapping immutable slices. + /// [`ParallelSliceMut::par_chunk_map_mut`] for mapping when a specific chunk size is desirable. fn par_splat_map_mut( &mut self, task_pool: &TaskPool, diff --git a/crates/bevy_tasks/src/task_pool.rs b/crates/bevy_tasks/src/task_pool.rs index bf23ef1a586c9..4d50555f92f37 100644 --- a/crates/bevy_tasks/src/task_pool.rs +++ b/crates/bevy_tasks/src/task_pool.rs @@ -229,6 +229,8 @@ impl TaskPool { /// Spawns a static future onto the thread pool. The returned Task is a future. It can also be /// cancelled and "detached" allowing it to continue running without having to be polled by the /// end-user. + /// + /// If the provided future is non-`Send`, [`TaskPool::spawn_local`] should be used instead. pub fn spawn(&self, future: impl Future + Send + 'static) -> Task where T: Send + 'static, @@ -236,6 +238,11 @@ impl TaskPool { Task::new(self.executor.spawn(future)) } + /// Spawns a static future on the thread-local async executor for the current thread. The task + /// will run entirely on the thread the task was spawned on. The returned Task is a future. + /// It can also be cancelled and "detached" allowing it to continue running without having + /// to be polled by the end-user. Users should generally prefer to use [`TaskPool::spawn`] + /// instead, unless the provided future is not `Send`. pub fn spawn_local(&self, future: impl Future + 'static) -> Task where T: 'static, @@ -250,6 +257,9 @@ impl Default for TaskPool { } } +/// A `TaskPool` scope for running one or more non-`'static` futures. +/// +/// For more information, see [`TaskPool::scope`]. #[derive(Debug)] pub struct Scope<'scope, T> { executor: &'scope async_executor::Executor<'scope>, @@ -258,11 +268,25 @@ pub struct Scope<'scope, T> { } impl<'scope, T: Send + 'scope> Scope<'scope, T> { + /// Spawns a scoped future onto the thread pool. The scope *must* outlive + /// the provided future. The results of the future will be returned as a part of + /// [`TaskPool::scope`]'s return value. + /// + /// If the provided future is non-`Send`, [`Scope::spawn_local`] should be used + /// instead. + /// + /// For more information, see [`TaskPool::scope`]. pub fn spawn + 'scope + Send>(&mut self, f: Fut) { let task = self.executor.spawn(f); self.spawned.push(task); } + /// Spawns a scoped future onto the thread-local executor. The scope *must* outlive + /// the provided future. The results of the future will be returned as a part of + /// [`TaskPool::scope`]'s return value. Users should generally prefer to use + /// [`Scope::spawn`] instead, unless the provided future is not `Send`. + /// + /// For more information, see [`TaskPool::scope`]. pub fn spawn_local + 'scope>(&mut self, f: Fut) { let task = self.local_executor.spawn(f); self.spawned.push(task);