Skip to content

Commit e1f7619

Browse files
committed
If a scope() has a single task, just execute it immediately on the calling thread.
1 parent 5fc894f commit e1f7619

File tree

1 file changed

+36
-32
lines changed

1 file changed

+36
-32
lines changed

crates/bevy_tasks/src/task_pool.rs

+36-32
Original file line numberDiff line numberDiff line change
@@ -167,44 +167,48 @@ impl TaskPool {
167167
let executor: &async_executor::Executor = &*self.executor;
168168
let executor: &'scope async_executor::Executor = unsafe { mem::transmute(executor) };
169169

170-
let fut = async move {
171-
let mut scope = Scope {
172-
executor,
173-
spawned: Vec::new(),
174-
};
170+
let mut scope = Scope {
171+
executor,
172+
spawned: Vec::new(),
173+
};
175174

176-
f(&mut scope);
175+
f(&mut scope);
177176

178-
let mut results = Vec::with_capacity(scope.spawned.len());
179-
for task in scope.spawned {
180-
results.push(task.await);
181-
}
177+
if scope.spawned.len() == 1 {
178+
vec![future::block_on(&mut scope.spawned[0])]
179+
} else {
180+
let fut = async move {
181+
let mut results = Vec::with_capacity(scope.spawned.len());
182+
for task in scope.spawned {
183+
results.push(task.await);
184+
}
182185

183-
results
184-
};
186+
results
187+
};
185188

186-
// Pin the future on the stack.
187-
pin!(fut);
189+
// Pin the future on the stack.
190+
pin!(fut);
191+
192+
// SAFETY: This function blocks until all futures complete, so we do not read/write the
193+
// data from futures outside of the 'scope lifetime. However, rust has no way of knowing
194+
// this so we must convert to 'static here to appease the compiler as it is unable to
195+
// validate safety.
196+
let fut: Pin<&mut (dyn Future<Output = Vec<T>> + Send)> = fut;
197+
let fut: Pin<&'static mut (dyn Future<Output = Vec<T>> + Send + 'static)> =
198+
unsafe { mem::transmute(fut) };
199+
200+
// The thread that calls scope() will participate in driving tasks in the pool forward
201+
// until the tasks that are spawned by this scope() call complete. (If the caller of scope()
202+
// happens to be a thread in this thread pool, and we only have one thread in the pool, then
203+
// simply calling future::block_on(spawned) would deadlock.)
204+
let mut spawned = self.executor.spawn(fut);
205+
loop {
206+
if let Some(result) = future::block_on(future::poll_once(&mut spawned)) {
207+
break result;
208+
}
188209

189-
// SAFETY: This function blocks until all futures complete, so we do not read/write the
190-
// data from futures outside of the 'scope lifetime. However, rust has no way of knowing
191-
// this so we must convert to 'static here to appease the compiler as it is unable to
192-
// validate safety.
193-
let fut: Pin<&mut (dyn Future<Output = Vec<T>> + Send)> = fut;
194-
let fut: Pin<&'static mut (dyn Future<Output = Vec<T>> + Send + 'static)> =
195-
unsafe { mem::transmute(fut) };
196-
197-
// The thread that calls scope() will participate in driving tasks in the pool forward
198-
// until the tasks that are spawned by this scope() call complete. (If the caller of scope()
199-
// happens to be a thread in this thread pool, and we only have one thread in the pool, then
200-
// simply calling future::block_on(spawned) would deadlock.)
201-
let mut spawned = self.executor.spawn(fut);
202-
loop {
203-
if let Some(result) = future::block_on(future::poll_once(&mut spawned)) {
204-
break result;
210+
self.executor.try_tick();
205211
}
206-
207-
self.executor.try_tick();
208212
}
209213
}
210214

0 commit comments

Comments
 (0)