Skip to content

deprecate SimpleExecutor #18753

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions benches/benches/bevy_ecs/scheduling/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ pub fn empty_schedule_run(criterion: &mut Criterion) {
});

let mut schedule = Schedule::default();
#[expect(deprecated, reason = "We still need to test/bench this.")]
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::Simple);
group.bench_function("Simple", |bencher| {
bencher.iter(|| schedule.run(app.world_mut()));
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_ecs/src/schedule/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod single_threaded;
use alloc::{borrow::Cow, vec, vec::Vec};
use core::any::TypeId;

#[expect(deprecated, reason = "We still need to support this.")]
pub use self::{simple::SimpleExecutor, single_threaded::SingleThreadedExecutor};

#[cfg(feature = "std")]
Expand Down Expand Up @@ -53,6 +54,10 @@ pub enum ExecutorKind {
SingleThreaded,
/// Like [`SingleThreaded`](ExecutorKind::SingleThreaded) but calls [`apply_deferred`](crate::system::System::apply_deferred)
/// immediately after running each system.
#[deprecated(
since = "0.17.0",
note = "Use SingleThreaded instead. See https://github.com/bevyengine/bevy/issues/18453 for motivation."
)]
Simple,
/// Runs the schedule using a thread pool. Non-conflicting systems can run in parallel.
#[cfg(feature = "std")]
Expand Down Expand Up @@ -325,6 +330,7 @@ mod tests {
struct TestComponent;

const EXECUTORS: [ExecutorKind; 3] = [
#[expect(deprecated, reason = "We still need to test this.")]
ExecutorKind::Simple,
ExecutorKind::SingleThreaded,
ExecutorKind::MultiThreaded,
Expand Down Expand Up @@ -382,6 +388,7 @@ mod tests {
let mut world = World::new();
let mut schedule = Schedule::default();

#[expect(deprecated, reason = "We still need to test this.")]
schedule.set_executor_kind(ExecutorKind::Simple);
schedule.add_systems(look_for_missing_resource);
schedule.run(&mut world);
Expand Down
11 changes: 10 additions & 1 deletion crates/bevy_ecs/src/schedule/executor/simple.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![expect(deprecated, reason = "Everything here is deprecated")]

use core::panic::AssertUnwindSafe;
use fixedbitset::FixedBitSet;

Expand All @@ -20,6 +22,10 @@ use super::__rust_begin_short_backtrace;
/// A variant of [`SingleThreadedExecutor`](crate::schedule::SingleThreadedExecutor) that calls
/// [`apply_deferred`](crate::system::System::apply_deferred) immediately after running each system.
#[derive(Default)]
#[deprecated(
since = "0.17.0",
note = "Use SingleThreadedExecutor instead. See https://github.com/bevyengine/bevy/issues/18453 for motivation."
)]
pub struct SimpleExecutor {
/// Systems sets whose conditions have been evaluated.
evaluated_sets: FixedBitSet,
Expand Down Expand Up @@ -165,7 +171,10 @@ impl SimpleExecutor {
}
}
}

#[deprecated(
since = "0.17.0",
note = "Use SingleThreadedExecutor instead. See https://github.com/bevyengine/bevy/issues/18453 for motivation."
)]
fn evaluate_and_fold_conditions(conditions: &mut [BoxedCondition], world: &mut World) -> bool {
let error_handler = default_error_handler();

Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ecs/src/schedule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,7 @@ mod tests {

/// verify the [`SimpleExecutor`] supports stepping
#[test]
#[expect(deprecated, reason = "We still need to test this.")]
fn simple_executor() {
assert_executor_supports_stepping!(ExecutorKind::Simple);
}
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ecs/src/schedule/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ impl Schedules {

fn make_executor(kind: ExecutorKind) -> Box<dyn SystemExecutor> {
match kind {
#[expect(deprecated, reason = "We still need to support this.")]
ExecutorKind::Simple => Box::new(SimpleExecutor::new()),
ExecutorKind::SingleThreaded => Box::new(SingleThreadedExecutor::new()),
#[cfg(feature = "std")]
Expand Down
25 changes: 25 additions & 0 deletions release-content/migration-guides/simple_executor_going_away.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: Deprecated Simple Executor
pull_requests: [18753]
---

Bevy has deprecated `SimpleExecutor`, one of the `SystemExecutor`s in Bevy alongside `SingleThreadedExecutor` and `MultiThreadedExecutor` (which aren't going anywhere any time soon).

The `SimpleExecutor` leaves performance on the table compared to the other executors in favor of simplicity.
Specifically, `SimpleExecutor` applies any commands a system produces right after it finishes, so every system starts with a clean `World` with no pending commands.
As a result, the default `SimpleExecutor` runs all systems in the order they are added to the schedule, though more ordering constraints can be applied, like `before`, `after`, `chain`, etc.
In other executors, these ordering onstraints also inform the executor exactly where to apply commands.
For example, if system `A` produces commands and runs `before` system `B`, `A`'s commands will be applied before `B` starts.
However, the `before` ordering is implicit in `SimpleExecutor` if `A` is added to the schedule before `B`.

The dueling behavior between ordering systems based on when they were added to a schedule as opposed to using ordering constraints is difficult to maintain and can be confusing, especially for new users.
But, if you have a strong preference for the existing behavior of `SimpleExecutor`, please make an issue and we can discuss your needs.

If you were using `SimpleExecutor`, consider upgrading to `SingleThreadedExecutor` instead, or try `MultiThreadedExecutor` if it fits the schedule.
The `MultiThreadedExecutor` is great at large schedules and async heavy work, and the `SingleThreadedExecutor` is good at smaller schedules or schedules that have fewer parallelizable systems.
So what was `SimpleExecutor` good at? Not much. That's why we plan to remove it. Removing it will reduce some maintenance and consistency burdens, allowing us to focus on more exciting features!

When migrating, you might uncover bugs where one system depends on another's commands but is not ordered to reflect that.
These bugs can be fixed by making those implicit orderings explicit via constraints like `before`, `after`, `chain`, etc.
If finding all of those implicit but necessary orderings is unrealistic, `chain` can also be used to mimic the behavior of the `SimpleExecutor`.
Again, if you run into trouble migrating, feel free to open an issue!