1#](https://github.com/bevyengine/bevy#license)\n[](https://crates.io/crates/bevy_tasks)\n[](https://crates.io/crates/bevy_tasks)\n[](https://docs.rs/bevy_tasks/latest/bevy_tasks/)\n[](https://discord.gg/bevy)\n\nA refreshingly simple task executor for bevy. :)\n\nThis is a simple threadpool with minimal dependencies. The main usecase is a scoped fork-join, i.e. spawning tasks from\na single thread and having that thread await the completion of those tasks. This is intended specifically for\n[`bevy`][bevy] as a lighter alternative to [`rayon`][rayon] for this specific usecase. There are also utilities for\ngenerating the tasks from a slice of data. This library is intended for games and makes no attempt to ensure fairness\nor ordering of spawned tasks.\n\nIt is based on [`async-executor`][async-executor], a lightweight executor that allows the end user to manage their own threads.\n`async-executor` is based on async-task, a core piece of async-std.\n\n## Usage\n\nIn order to be able to optimize task execution in multi-threaded environments,\nbevy provides three different thread pools via which tasks of different kinds can be spawned.\n(The same API is used in single-threaded environments, even if execution is limited to a single thread.\nThis currently applies to Wasm targets.)\nThe determining factor for what kind of work should go in each pool is latency requirements:\n\n* For CPU-intensive work (tasks that generally spin until completion) we have a standard\n [`ComputeTaskPool`] and an [`AsyncComputeTaskPool`]. Work that does not need to be completed to\n present the next frame should go to the [`AsyncComputeTaskPool`].\n\n* For IO-intensive work (tasks that spend very little time in a \"woken\" state) we have an\n [`IoTaskPool`] whose tasks are expected to complete very quickly. Generally speaking, they should just\n await receiving data from somewhere (i.e. disk) and signal other systems when the data is ready\n for consumption. (likely via channels)\n\n## `no_std` Support\n\nTo enable `no_std` support in this crate, you will need to disable default features, and enable the `edge_executor` and `critical-section` features.\n\n[bevy]: https://bevy.org\n[rayon]: https://github.com/rayon-rs/rayon\n[async-executor]: https://github.com/stjepang/async-executor\n"include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc(
4 html_logo_url = "https://bevy.org/assets/icon.png",
5 html_favicon_url = "https://bevy.org/assets/icon.png"
6)]
7#![no_std]
89/// Configuration information for this crate.
10pub mod cfg {
11pub(crate) use bevy_platform::cfg::*;
1213pub use bevy_platform::cfg::{alloc, std, web};
1415#[doc = r" Indicates multithreading support."]
#[doc(inline)]
#[doc = r""]
#[doc =
"This macro passes the provided code because `#[cfg(all(not(target_arch = \"wasm32\"), feature = \"multi_threaded\"))]` is currently active."]
pub use ::bevy_platform::enabled as multi_threaded;
#[doc = r" Indicates the current target requires additional `Send` bounds."]
#[doc(inline)]
#[doc = r""]
#[doc =
"This macro suppresses the provided code because `#[cfg(target_arch = \"wasm32\")]` is _not_ currently active."]
pub use ::bevy_platform::disabled as conditional_send;define_alias! {
16#[cfg(feature = "async_executor")] => {
17/// Indicates `async_executor` is used as the future execution backend.
18async_executor
19 }
2021#[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))] => {
22/// Indicates multithreading support.
23multi_threaded
24 }
2526#[cfg(target_arch = "wasm32")] => {
27/// Indicates the current target requires additional `Send` bounds.
28conditional_send
29 }
3031 }32}
3334cfg::std! {
35extern crate std;
36}
3738extern crate alloc;
3940cfg::conditional_send! {
41if {
42/// Use [`ConditionalSend`] to mark an optional Send trait bound. Useful as on certain platforms (eg. Wasm),
43 /// futures aren't Send.
44pub trait ConditionalSend {}
45impl<T> ConditionalSend for T {}
46 } else {
47/// Use [`ConditionalSend`] to mark an optional Send trait bound. Useful as on certain platforms (eg. Wasm),
48 /// futures aren't Send.
49pub trait ConditionalSend: Send {}
50impl<T: Send> ConditionalSendfor T {}
51 }
52}
5354/// Use [`ConditionalSendFuture`] for a future with an optional Send trait bound, as on certain platforms (eg. Wasm),
55/// futures aren't Send.
56pub trait ConditionalSendFuture: Future + ConditionalSend {}
5758impl<T: Future + ConditionalSend> ConditionalSendFuturefor T {}
5960use alloc::boxed::Box;
6162/// An owned and dynamically typed Future used when you can't statically type your result or need to add some indirection.
63pub type BoxedFuture<'a, T> = core::pin::Pin<Box<dyn ConditionalSendFuture<Output = T> + 'a>>;
6465// Modules
66mod executor;
67pub mod futures;
68mod iter;
69mod slice;
70mod usages;
7172cfg::async_executor! {
73if {} else {
74mod edge_executor;
75 }
76}
7778// Exports
79pub use async_task::Task;
80pub use iter::ParallelIterator;
81pub use slice::{ParallelSlice, ParallelSliceMut};
82pub use usages::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool};
8384pub use futures_lite;
85pub use futures_lite::future::poll_once;
8687cfg::web! {
88if {} else {
89pub use usages::tick_global_task_pools_on_main_thread;
90 }
91}
9293cfg::multi_threaded! {
94if {
95mod task_pool;
96mod thread_executor;
9798pub use task_pool::{Scope, TaskPool, TaskPoolBuilder};
99pub use thread_executor::{ThreadExecutor, ThreadExecutorTicker};
100 } else {
101mod single_threaded_task_pool;
102103pub use single_threaded_task_pool::{Scope, TaskPool, TaskPoolBuilder, ThreadExecutor};
104 }
105}
106107pub use bevy_platform::future::block_on;
108109/// The tasks prelude.
110///
111/// This includes the most common types in this crate, re-exported for your convenience.
112pub mod prelude {
113#[doc(hidden)]
114pub use crate::{
115block_on,
116iter::ParallelIterator,
117 slice::{ParallelSlice, ParallelSliceMut},
118 usages::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool},
119 };
120}
121122/// Gets the logical CPU core count available to the current process.
123///
124/// This is identical to `std::thread::available_parallelism`, except
125/// it will return a default value of 1 if it internally errors out.
126///
127/// This will always return at least 1.
128pub fn available_parallelism() -> usize {
129{
std::thread::available_parallelism().map(core::num::NonZero::<usize>::get).unwrap_or(1)
}cfg::switch! {{
130 cfg::std => {
131 std::thread::available_parallelism()
132 .map(core::num::NonZero::<usize>::get)
133 .unwrap_or(1)
134 }
135_ => {
1361
137}
138 }}139}