Skip to content
Open
Show file tree
Hide file tree
Changes from 74 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
3691690
Inline async_executor
james7132 Jul 26, 2025
54b0bbc
Merge LocalExecutor into the Executor implementation
james7132 Jul 26, 2025
2b8ed66
Merge ThreadEecutors into the new forked async_executor
james7132 Jul 27, 2025
1121542
Move stealer queues to TLS storage. Avoid extra Arc allocations
james7132 Jul 27, 2025
01ac223
Queue tasks directly back onto local queues to avoid global injector …
james7132 Jul 28, 2025
1dab08e
Use UnsafeCell instead of RefCell
james7132 Jul 28, 2025
0b036fe
Optimize access of thread locked tasks
james7132 Jul 28, 2025
45b5e15
Clean up unnecessary unsafe use
james7132 Jul 29, 2025
ab45573
Address potential unsoundness with ThreadSpawner
james7132 Jul 30, 2025
05f1f40
Fix some CI errors
james7132 Jul 30, 2025
0f226bf
Update docs
james7132 Jul 30, 2025
9c28473
Format TOML files
james7132 Jul 30, 2025
7f8c932
Make note on ThreadLocal soundness hole
james7132 Jul 30, 2025
f84028e
Allow clippy warning
james7132 Jul 30, 2025
f44d302
Fix typos
james7132 Jul 30, 2025
227258e
Try to fix CI outside of miri
james7132 Jul 30, 2025
d88035d
Remove depnedency on concurrent-queue
james7132 Aug 2, 2025
2028736
Revert "Clean up unnecessary unsafe use"
james7132 Aug 2, 2025
da66005
Fix single-threaded builds
james7132 Aug 3, 2025
8d4e5ca
Fix builds for no_std builds
james7132 Aug 3, 2025
3cb694f
Shut up Clippy
james7132 Aug 3, 2025
d0ef3f4
Fix bevy_ecs builds
james7132 Aug 3, 2025
25233ff
Whoops
james7132 Aug 3, 2025
69a1389
Arc is only used when no_std
james7132 Aug 3, 2025
943f135
Remove now unused mentions of LocalExecutor
james7132 Aug 3, 2025
5b9a40e
Remove unused import
james7132 Aug 3, 2025
355c96f
Use pin_project_lite for web builds instead of pin_project
james7132 Aug 3, 2025
564daf6
Fix TOML formatting
james7132 Aug 3, 2025
b100634
Make CatchUnwind pin_project_lite friendly
james7132 Aug 3, 2025
8700f7e
Add missing AssertUnwindSafe
james7132 Aug 3, 2025
a94bfda
Merge branch 'main' into bevy_executor
james7132 Aug 4, 2025
6246ec8
Another attempt at fixing CI
james7132 Aug 4, 2025
6faca4f
Merge branch 'main' into bevy_executor
james7132 Aug 5, 2025
93c696b
Properly handle thread destruction and recycling
james7132 Aug 5, 2025
686d429
Switch to a solution that doesn't require TLS access in thread destru…
james7132 Aug 6, 2025
aa64f03
Try to provide a blocking solution to TaskPool::scope in single threa…
james7132 Aug 6, 2025
1d73b78
Merge branch 'main' into bevy_executor
james7132 Aug 6, 2025
79c31b7
CI fixes
james7132 Aug 8, 2025
fc875d9
Merge branch 'main' into bevy_executor
james7132 Aug 10, 2025
4dcb37c
Fix up the build, and hopefully CI
james7132 Aug 10, 2025
0923f02
Shut up Clippy
james7132 Aug 10, 2025
43a09d7
Remove test println
james7132 Aug 10, 2025
8f313f7
Fix for portable atomics
james7132 Aug 10, 2025
4a8b6b0
Fix for web builds
james7132 Aug 10, 2025
7e5cf6c
Reduce async type genreation, code indirection, and handle single-thr…
james7132 Aug 11, 2025
eb689b5
Fix docs and move expect attribute
james7132 Aug 11, 2025
7ec07af
Complete the comment
james7132 Aug 11, 2025
4a4434c
Add async_executor's tests
james7132 Aug 11, 2025
2ce5537
Run Miri on bevy_tasks in CI
james7132 Aug 11, 2025
8af9886
Make stealing a non-blocking operation
james7132 Aug 11, 2025
cfc6af4
Merge branch 'main' into bevy_executor
james7132 Aug 11, 2025
74d301c
Cache-pad the thread locals and disable multithreaded polling when th…
james7132 Aug 12, 2025
898166b
Fix Miri job to run them in sequence
james7132 Aug 12, 2025
2b96789
Fix up README and Clippy
james7132 Aug 12, 2025
f5737f7
It's clippy
james7132 Aug 12, 2025
84edd4f
Address UB in spawn_scoped_local from OOMs
james7132 Aug 15, 2025
dc7ce63
Move expect to outer block
james7132 Aug 15, 2025
b217cbd
Merge branch 'main' into bevy_executor
james7132 Aug 15, 2025
00b62c2
Fix lint
james7132 Aug 19, 2025
5d122a0
Go back to using ConcurrentQueue
james7132 Aug 19, 2025
73798b1
Don't panic
james7132 Aug 19, 2025
909f2e5
Formatting
james7132 Aug 19, 2025
96dd3d5
is_multiple_of lint
james7132 Aug 20, 2025
6c4f878
Merge branch 'main' into bevy_executor
james7132 Aug 22, 2025
b10d226
Minimize cfg blocks
james7132 Aug 24, 2025
e8b9c1f
Try getting rid of the main thread local executor tick system
james7132 Aug 24, 2025
3354efa
Use a proper struct for Sleepers
james7132 Aug 25, 2025
c6fecbd
Update module docs
james7132 Aug 25, 2025
5df82e1
Remove unused code
james7132 Aug 25, 2025
ee8f531
Cleanup using utilities we already have
james7132 Aug 25, 2025
20fe27b
Avoid the extra Waker clone when initially scheduling tasks
james7132 Aug 28, 2025
ea262ef
Clippy, formatting, and panic documentation
james7132 Aug 28, 2025
f305276
Rename ThreadSpawner -> LocalTaskSpawner
james7132 Sep 1, 2025
5373e7c
Fix macro
james7132 Sep 1, 2025
9c35b81
Spin loop hints
james7132 Sep 4, 2025
ded5b15
Merge branch 'main' into bevy_executor
james7132 Sep 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ jobs:
miri:
runs-on: macos-latest
timeout-minutes: 60
env:
# -Zrandomize-layout makes sure we dont rely on the layout of anything that might change
RUSTFLAGS: -Zrandomize-layout
# https://github.com/rust-lang/miri#miri--z-flags-and-environment-variables
# -Zmiri-disable-isolation is needed because our executor uses `fastrand` which accesses system time.
# -Zmiri-ignore-leaks is necessary because a bunch of tests don't join all threads before finishing.
MIRIFLAGS: -Zmiri-ignore-leaks -Zmiri-disable-isolation
steps:
- uses: actions/checkout@v5
- uses: actions/cache/restore@v4
Expand All @@ -111,17 +118,14 @@ jobs:
with:
toolchain: ${{ env.NIGHTLY_TOOLCHAIN }}
components: miri
- name: CI job
- name: CI job (Tasks)
# To run the tests one item at a time for troubleshooting, use
# cargo --quiet test --lib -- --list | sed 's/: test$//' | MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation" xargs -n1 cargo miri test -p bevy_tasks --lib -- --exact
run: cargo miri test -p bevy_tasks --features bevy_executor --features multi_threaded
- name: CI job (ECS)
# To run the tests one item at a time for troubleshooting, use
# cargo --quiet test --lib -- --list | sed 's/: test$//' | MIRIFLAGS="-Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation" xargs -n1 cargo miri test -p bevy_ecs --lib -- --exact
run: cargo miri test -p bevy_ecs --features bevy_utils/debug
env:
# -Zrandomize-layout makes sure we dont rely on the layout of anything that might change
RUSTFLAGS: -Zrandomize-layout
# https://github.com/rust-lang/miri#miri--z-flags-and-environment-variables
# -Zmiri-disable-isolation is needed because our executor uses `fastrand` which accesses system time.
# -Zmiri-ignore-leaks is necessary because a bunch of tests don't join all threads before finishing.
MIRIFLAGS: -Zmiri-ignore-leaks -Zmiri-disable-isolation

check-compiles:
runs-on: ubuntu-latest
Expand Down
4 changes: 0 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ unused_qualifications = "warn"
[features]
default = [
"std",
"async_executor",
"android-game-activity",
"android_shared_stdcxx",
"animation",
Expand Down Expand Up @@ -586,9 +585,6 @@ custom_cursor = ["bevy_internal/custom_cursor"]
# Experimental support for nodes that are ignored for UI layouting
ghost_nodes = ["bevy_internal/ghost_nodes"]

# Uses `async-executor` as a task execution backend.
async_executor = ["std", "bevy_internal/async_executor"]

# Allows access to the `std` crate.
std = ["bevy_internal/std"]

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_a11y/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
keywords = ["bevy", "accessibility", "a11y"]

[features]
default = ["std", "bevy_reflect", "bevy_ecs/async_executor"]
default = ["std", "bevy_reflect"]

# Functionality

Expand Down
5 changes: 1 addition & 4 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1401,10 +1401,7 @@ impl Plugin for HokeyPokey {
type RunnerFn = Box<dyn FnOnce(App) -> AppExit>;

fn run_once(mut app: App) -> AppExit {
while app.plugins_state() == PluginsState::Adding {
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
bevy_tasks::tick_global_task_pools_on_main_thread();
}
while app.plugins_state() == PluginsState::Adding {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm might need to revert the tick_global_task_pools_on_main_thread changes, some of the examples are failling. May need to implement a block_on based on Executor::run here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I investigated why we needed the tick_global_task_pools_on_main_thread in the runners. It started in #8336 and was added to run the IoTask for initializing the renderer. This works in native single threaded, because we run the tasks inline in the spawn. On web this works since we detach the task and poll for the RenderDevice in finish. So the one case I can think of where this might matter is if we're running multithreaded, but we don't spawn any worker threads. I'd be a bit surprised if that's what's happening in ci, since I thought we spawned at least 1 thread in each pool by default.

app.finish();
app.cleanup();

Expand Down
5 changes: 1 addition & 4 deletions crates/bevy_app/src/schedule_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ impl Plugin for ScheduleRunnerPlugin {
app.set_runner(move |mut app: App| {
let plugins_state = app.plugins_state();
if plugins_state != PluginsState::Cleaned {
while app.plugins_state() == PluginsState::Adding {
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
bevy_tasks::tick_global_task_pools_on_main_thread();
}
while app.plugins_state() == PluginsState::Adding {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should use hint::spin_loop

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this be able to make progress to spawned tasks in single threaded mode? I thought that was why tick_global_task_pools_on_main_thread was added originally.

app.finish();
app.cleanup();
}
Expand Down
18 changes: 0 additions & 18 deletions crates/bevy_app/src/task_pool_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,6 @@ use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuil
use core::fmt::Debug;
use log::trace;

cfg_if::cfg_if! {
if #[cfg(not(all(target_arch = "wasm32", feature = "web")))] {
use {crate::Last, bevy_tasks::tick_global_task_pools_on_main_thread};
use bevy_ecs::system::NonSendMarker;

/// A system used to check and advanced our task pools.
///
/// Calls [`tick_global_task_pools_on_main_thread`],
/// and uses [`NonSendMarker`] to ensure that this system runs on the main thread
fn tick_global_task_pools(_main_thread_marker: NonSendMarker) {
tick_global_task_pools_on_main_thread();
}
}
}

/// Setup of default task pools: [`AsyncComputeTaskPool`], [`ComputeTaskPool`], [`IoTaskPool`].
#[derive(Default)]
pub struct TaskPoolPlugin {
Expand All @@ -32,9 +17,6 @@ impl Plugin for TaskPoolPlugin {
fn build(&self, _app: &mut App) {
// Setup the default bevy task pools
self.task_pool_options.create_default_pools();

#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
_app.add_systems(Last, tick_global_task_pools);
}
}

Expand Down
4 changes: 1 addition & 3 deletions crates/bevy_asset/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.17.0-dev", default-features = fa
bevy_reflect = { path = "../bevy_reflect", version = "0.17.0-dev", default-features = false, features = [
"uuid",
] }
bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev", default-features = false, features = [
"async_executor",
] }
bevy_tasks = { path = "../bevy_tasks", version = "0.17.0-dev", default-features = false }
bevy_utils = { path = "../bevy_utils", version = "0.17.0-dev", default-features = false }
bevy_platform = { path = "../bevy_platform", version = "0.17.0-dev", default-features = false, features = [
"std",
Expand Down
8 changes: 1 addition & 7 deletions crates/bevy_ecs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ categories = ["game-engines", "data-structures"]
rust-version = "1.86.0"

[features]
default = ["std", "bevy_reflect", "async_executor", "backtrace"]
default = ["std", "bevy_reflect", "backtrace"]

# Functionality

Expand Down Expand Up @@ -49,12 +49,6 @@ bevy_debug_stepping = []
## This will often provide more detailed error messages.
track_location = []

# Executor Backend

## Uses `async-executor` as a task execution backend.
## This backend is incompatible with `no_std` targets.
async_executor = ["std", "bevy_tasks/async_executor"]

# Platform Compatibility

## Allows access to the `std` crate. Enabling this feature will prevent compilation
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/schedule/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use core::any::TypeId;
pub use self::{simple::SimpleExecutor, single_threaded::SingleThreadedExecutor};

#[cfg(feature = "std")]
pub use self::multi_threaded::{MainThreadExecutor, MultiThreadedExecutor};
pub use self::multi_threaded::{MainThreadTaskSpawner, MultiThreadedExecutor};

use fixedbitset::FixedBitSet;

Expand Down
17 changes: 7 additions & 10 deletions crates/bevy_ecs/src/schedule/executor/multi_threaded.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use alloc::{boxed::Box, vec::Vec};
use bevy_platform::cell::SyncUnsafeCell;
use bevy_platform::sync::Arc;
use bevy_tasks::{ComputeTaskPool, Scope, TaskPool, ThreadExecutor};
use bevy_tasks::{ComputeTaskPool, LocalTaskSpawner, Scope, TaskPool};
use concurrent_queue::ConcurrentQueue;
use core::{any::Any, panic::AssertUnwindSafe};
use fixedbitset::FixedBitSet;
Expand Down Expand Up @@ -270,14 +269,12 @@ impl SystemExecutor for MultiThreadedExecutor {
}

let thread_executor = world
.get_resource::<MainThreadExecutor>()
.get_resource::<MainThreadTaskSpawner>()
.map(|e| e.0.clone());
let thread_executor = thread_executor.as_deref();

let environment = &Environment::new(self, schedule, world);

ComputeTaskPool::get_or_init(TaskPool::default).scope_with_executor(
false,
thread_executor,
|scope| {
let context = Context {
Expand Down Expand Up @@ -864,20 +861,20 @@ unsafe fn evaluate_and_fold_conditions(
.fold(true, |acc, res| acc && res)
}

/// New-typed [`ThreadExecutor`] [`Resource`] that is used to run systems on the main thread
/// New-typed [`LocalTaskSpawner`] [`Resource`] that is used to run systems on the main thread
#[derive(Resource, Clone)]
pub struct MainThreadExecutor(pub Arc<ThreadExecutor<'static>>);
pub struct MainThreadTaskSpawner(pub LocalTaskSpawner<'static>);

impl Default for MainThreadExecutor {
impl Default for MainThreadTaskSpawner {
fn default() -> Self {
Self::new()
}
}

impl MainThreadExecutor {
impl MainThreadTaskSpawner {
/// Creates a new executor that can be used to run systems on the main thread.
pub fn new() -> Self {
MainThreadExecutor(TaskPool::get_thread_executor())
MainThreadTaskSpawner(ComputeTaskPool::get().current_thread_spawner())
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_input/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
keywords = ["bevy"]

[features]
default = ["std", "bevy_reflect", "bevy_ecs/async_executor", "smol_str"]
default = ["std", "bevy_reflect", "smol_str"]

# Functionality

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_input_focus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ keywords = ["bevy"]
rust-version = "1.85.0"

[features]
default = ["std", "bevy_reflect", "bevy_ecs/async_executor"]
default = ["std", "bevy_reflect"]

# Functionality

Expand Down
9 changes: 0 additions & 9 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -383,15 +383,6 @@ libm = [
"bevy_window?/libm",
]

# Uses `async-executor` as a task execution backend.
# This backend is incompatible with `no_std` targets.
async_executor = [
"std",
"bevy_tasks/async_executor",
"bevy_ecs/async_executor",
"bevy_transform/async_executor",
]

# Enables use of browser APIs.
# Note this is currently only applicable on `wasm32` architectures.
web = ["bevy_app/web", "bevy_platform/web", "bevy_reflect/web"]
Expand Down
10 changes: 5 additions & 5 deletions crates/bevy_render/src/pipelined_rendering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use async_channel::{Receiver, Sender};
use bevy_app::{App, AppExit, AppLabel, Plugin, SubApp};
use bevy_ecs::{
resource::Resource,
schedule::MainThreadExecutor,
schedule::MainThreadTaskSpawner,
world::{Mut, World},
};
use bevy_tasks::ComputeTaskPool;
Expand Down Expand Up @@ -114,7 +114,7 @@ impl Plugin for PipelinedRenderingPlugin {
if app.get_sub_app(RenderApp).is_none() {
return;
}
app.insert_resource(MainThreadExecutor::new());
app.insert_resource(MainThreadTaskSpawner::new());

let mut sub_app = SubApp::new();
sub_app.set_extract(renderer_extract);
Expand All @@ -136,7 +136,7 @@ impl Plugin for PipelinedRenderingPlugin {
.expect("Unable to get RenderApp. Another plugin may have removed the RenderApp before PipelinedRenderingPlugin");

// clone main thread executor to render world
let executor = app.world().get_resource::<MainThreadExecutor>().unwrap();
let executor = app.world().get_resource::<MainThreadTaskSpawner>().unwrap();
render_app.world_mut().insert_resource(executor.clone());

render_to_app_sender.send_blocking(render_app).unwrap();
Expand Down Expand Up @@ -181,12 +181,12 @@ impl Plugin for PipelinedRenderingPlugin {
// This function waits for the rendering world to be received,
// runs extract, and then sends the rendering world back to the render thread.
fn renderer_extract(app_world: &mut World, _world: &mut World) {
app_world.resource_scope(|world, main_thread_executor: Mut<MainThreadExecutor>| {
app_world.resource_scope(|world, main_thread_executor: Mut<MainThreadTaskSpawner>| {
world.resource_scope(|world, mut render_channels: Mut<RenderAppChannels>| {
// we use a scope here to run any main thread tasks that the render world still needs to run
// while we wait for the render world to be received.
if let Some(mut render_app) = ComputeTaskPool::get()
.scope_with_executor(true, Some(&*main_thread_executor.0), |s| {
.scope_with_executor(Some(main_thread_executor.0.clone()), |s| {
s.spawn(async { render_channels.recv().await });
})
.pop()
Expand Down
36 changes: 21 additions & 15 deletions crates/bevy_tasks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,24 @@ license = "MIT OR Apache-2.0"
keywords = ["bevy"]

[features]
default = ["async_executor", "futures-lite"]
default = ["futures-lite"]

# Enables multi-threading support.
# Without this feature, all tasks will be run on a single thread.
multi_threaded = [
"bevy_platform/std",
"dep:async-channel",
"dep:concurrent-queue",
"async_executor",
]
multi_threaded = ["bevy_platform/std", "dep:async-channel", "bevy_executor"]

# Uses `async-executor` as a task execution backend.
# Uses a Bevy-specific fork of `async-executor` as a task execution backend.
# This backend is incompatible with `no_std` targets.
async_executor = ["bevy_platform/std", "dep:async-executor", "futures-lite"]
bevy_executor = [
"dep:fastrand",
"dep:slab",
"dep:thread_local",
"dep:crossbeam-utils",
"dep:pin-project-lite",
"futures-lite",
"async-task/std",
"concurrent-queue/std",
]

# Provide an implementation of `block_on` from `futures-lite`.
futures-lite = ["bevy_platform/std", "futures-lite/std"]
Expand All @@ -44,18 +48,19 @@ derive_more = { version = "2", default-features = false, features = [
"deref",
"deref_mut",
] }
async-executor = { version = "1.11", optional = true }
slab = { version = "0.4", optional = true }
pin-project-lite = { version = "0.2", optional = true }
thread_local = { version = "1.1", optional = true }
fastrand = { version = "2.3", optional = true, default-features = false }
async-channel = { version = "2.3.0", optional = true }
async-io = { version = "2.0.0", optional = true }
concurrent-queue = { version = "2.0.0", optional = true }
atomic-waker = { version = "1", default-features = false }
crossbeam-queue = { version = "0.3", default-features = false, features = [
"alloc",
] }
concurrent-queue = { version = "2.5", default-features = false }
crossbeam-utils = { version = "0.8", default-features = false, optional = true }

[target.'cfg(target_arch = "wasm32")'.dependencies]
pin-project = "1"
async-channel = "2.3.0"
pin-project-lite = "0.2"

[target.'cfg(not(all(target_has_atomic = "8", target_has_atomic = "16", target_has_atomic = "32", target_has_atomic = "64", target_has_atomic = "ptr")))'.dependencies]
async-task = { version = "4.4.0", default-features = false, features = [
Expand All @@ -73,6 +78,7 @@ futures-lite = { version = "2.0.1", default-features = false, features = [
"std",
] }
async-channel = "2.3.0"
async-io = "2.0.0"

[lints]
workspace = true
Expand Down
8 changes: 5 additions & 3 deletions crates/bevy_tasks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ a single thread and having that thread await the completion of those tasks. This
generating the tasks from a slice of data. This library is intended for games and makes no attempt to ensure fairness
or ordering of spawned tasks.

It is based on [`async-executor`][async-executor], a lightweight executor that allows the end user to manage their own threads.
`async-executor` is based on async-task, a core piece of async-std.
It is based on a fork of [`async-executor`][async-executor], a lightweight executor that allows the end user to manage their own threads.
`async-executor` is based on [`async-task`][async-task], a core piece of [`smol`][smol].

## Usage

Expand All @@ -40,4 +40,6 @@ To enable `no_std` support in this crate, you will need to disable default featu

[bevy]: https://bevy.org
[rayon]: https://github.com/rayon-rs/rayon
[async-executor]: https://github.com/stjepang/async-executor
[async-executor]: https://github.com/smol-rs/async-executor
[smol]: https://github.com/smol-rs/smol
[async-task]: https://github.com/smol-rs/async-task
Loading
Loading