mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Immediately poll the executor once before spawning it as a task (#11801)
# Objective At the start of every schedule run, there's currently a guaranteed piece of overhead as the async executor spawns the MultithreadeExecutor task onto one of the ComputeTaskPool threads. ## Solution Poll the executor once to immediately schedule systems without waiting for the async executor, then spawn the task if and only if the executor does not immediately terminate. On a similar note, having the executor task immediately start executing a system in the same async task might yield similar results over a broader set of cases. However, this might be more involved, and may need a solution like #8304.
This commit is contained in:
parent
bd25135330
commit
87add5660f
2 changed files with 13 additions and 5 deletions
|
@ -3,7 +3,7 @@ use std::{
|
|||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use bevy_tasks::{ComputeTaskPool, Scope, TaskPool, ThreadExecutor};
|
||||
use bevy_tasks::{block_on, poll_once, ComputeTaskPool, Scope, TaskPool, ThreadExecutor};
|
||||
use bevy_utils::default;
|
||||
use bevy_utils::syncunsafecell::SyncUnsafeCell;
|
||||
#[cfg(feature = "trace")]
|
||||
|
@ -227,7 +227,8 @@ impl SystemExecutor for MultiThreadedExecutor {
|
|||
|scope| {
|
||||
// the executor itself is a `Send` future so that it can run
|
||||
// alongside systems that claim the local thread
|
||||
let executor = async {
|
||||
#[allow(unused_mut)]
|
||||
let mut executor = Box::pin(async {
|
||||
let world_cell = world.as_unsafe_world_cell();
|
||||
while self.num_completed_systems < self.num_systems {
|
||||
// SAFETY:
|
||||
|
@ -252,13 +253,19 @@ impl SystemExecutor for MultiThreadedExecutor {
|
|||
self.rebuild_active_access();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
let executor_span = info_span!("multithreaded executor");
|
||||
#[cfg(feature = "trace")]
|
||||
let executor = executor.instrument(executor_span);
|
||||
scope.spawn(executor);
|
||||
let mut executor = executor.instrument(executor_span);
|
||||
|
||||
// Immediately poll the task once to avoid the overhead of the executor
|
||||
// and thread wake-up. Only spawn the task if the executor does not immediately
|
||||
// terminate.
|
||||
if block_on(poll_once(&mut executor)).is_none() {
|
||||
scope.spawn(executor);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ pub use thread_executor::{ThreadExecutor, ThreadExecutorTicker};
|
|||
pub use async_io::block_on;
|
||||
#[cfg(not(feature = "async-io"))]
|
||||
pub use futures_lite::future::block_on;
|
||||
pub use futures_lite::future::poll_once;
|
||||
|
||||
mod iter;
|
||||
pub use iter::ParallelIterator;
|
||||
|
|
Loading…
Reference in a new issue