Skip to main content

bevy_tasks/
lib.rs

1#![doc = "# Bevy Tasks\n\n[![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/bevyengine/bevy#license)\n[![Crates.io](https://img.shields.io/crates/v/bevy.svg)](https://crates.io/crates/bevy_tasks)\n[![Downloads](https://img.shields.io/crates/d/bevy_tasks.svg)](https://crates.io/crates/bevy_tasks)\n[![Docs](https://docs.rs/bevy_tasks/badge.svg)](https://docs.rs/bevy_tasks/latest/bevy_tasks/)\n[![Discord](https://img.shields.io/discord/691052431525675048.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](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]
8
9/// Configuration information for this crate.
10pub mod cfg {
11    pub(crate) use bevy_platform::cfg::*;
12
13    pub use bevy_platform::cfg::{alloc, std, web};
14
15    #[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.
18            async_executor
19        }
20
21        #[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))] => {
22            /// Indicates multithreading support.
23            multi_threaded
24        }
25
26        #[cfg(target_arch = "wasm32")] => {
27            /// Indicates the current target requires additional `Send` bounds.
28            conditional_send
29        }
30
31    }
32}
33
34cfg::std! {
35    extern crate std;
36}
37
38extern crate alloc;
39
40cfg::conditional_send! {
41    if {
42        /// Use [`ConditionalSend`] to mark an optional Send trait bound. Useful as on certain platforms (eg. Wasm),
43        /// futures aren't Send.
44        pub trait ConditionalSend {}
45        impl<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.
49        pub trait ConditionalSend: Send {}
50        impl<T: Send> ConditionalSend for T {}
51    }
52}
53
54/// 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 {}
57
58impl<T: Future + ConditionalSend> ConditionalSendFuture for T {}
59
60use alloc::boxed::Box;
61
62/// 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>>;
64
65// Modules
66mod executor;
67pub mod futures;
68mod iter;
69mod slice;
70mod usages;
71
72cfg::async_executor! {
73    if {} else {
74        mod edge_executor;
75    }
76}
77
78// Exports
79pub use async_task::Task;
80pub use iter::ParallelIterator;
81pub use slice::{ParallelSlice, ParallelSliceMut};
82pub use usages::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool};
83
84pub use futures_lite;
85pub use futures_lite::future::poll_once;
86
87cfg::web! {
88    if {} else {
89        pub use usages::tick_global_task_pools_on_main_thread;
90    }
91}
92
93cfg::multi_threaded! {
94    if {
95        mod task_pool;
96        mod thread_executor;
97
98        pub use task_pool::{Scope, TaskPool, TaskPoolBuilder};
99        pub use thread_executor::{ThreadExecutor, ThreadExecutorTicker};
100    } else {
101        mod single_threaded_task_pool;
102
103        pub use single_threaded_task_pool::{Scope, TaskPool, TaskPoolBuilder, ThreadExecutor};
104    }
105}
106
107pub use bevy_platform::future::block_on;
108
109/// 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)]
114    pub use crate::{
115        block_on,
116        iter::ParallelIterator,
117        slice::{ParallelSlice, ParallelSliceMut},
118        usages::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool},
119    };
120}
121
122/// 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        _ => {
136            1
137        }
138    }}
139}