From 117096659d418952da308f77beef0b3413c64c2c Mon Sep 17 00:00:00 2001 From: james7132 Date: Wed, 27 Aug 2025 21:53:42 -0700 Subject: [PATCH] Directly schedule tasks instead of using Runnable::schedule --- Cargo.toml | 3 +++ src/lib.rs | 15 ++++++++++---- src/static_executors.rs | 46 ++++++++++++++++++++++++++++++++--------- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ab39b0d..8483400 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,9 @@ exclude = ["/.*"] # Adds support for executors optimized for use in static variables. static = [] +[lib] +bench = false + [dependencies] async-task = "4.4.0" concurrent-queue = "2.5.0" diff --git a/src/lib.rs b/src/lib.rs index 615b5c4..33fbdd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -282,7 +282,10 @@ impl<'a> Executor<'a> { .spawn_unchecked(|()| future, Self::schedule(state)); entry.insert(runnable.waker()); - runnable.schedule(); + // `Runnable::schedule` has an extra clone/drop of the Waker, which can + // be skipped by directly scheduling instead of calling `Runnable::schedule`. + Self::schedule_runnable(&state, runnable); + task } @@ -353,12 +356,16 @@ impl<'a> Executor<'a> { fn schedule(state: Pin<&'a State>) -> impl Fn(Runnable) + Send + Sync + 'a { // TODO: If possible, push into the current local queue and notify the ticker. move |runnable| { - let result = state.queue.push(runnable); - debug_assert!(result.is_ok()); // Since we use unbounded queue, push will never fail. - state.notify(); + Self::schedule_runnable(&state, runnable); } } + fn schedule_runnable(state: &State, runnable: Runnable) { + let result = state.queue.push(runnable); + debug_assert!(result.is_ok()); // Since we use unbounded queue, push will never fail. + state.notify(); + } + /// Returns a pointer to the inner state. #[inline] fn state(&self) -> Pin<&'a State> { diff --git a/src/static_executors.rs b/src/static_executors.rs index 2ad0403..b1e8567 100644 --- a/src/static_executors.rs +++ b/src/static_executors.rs @@ -192,7 +192,11 @@ impl StaticExecutor { let (runnable, task) = Builder::new() .propagate_panic(true) .spawn(|()| future, self.schedule()); - runnable.schedule(); + + // `Runnable::schedule` has an extra clone/drop of the Waker, which can + // be skipped by directly scheduling instead of calling `Runnable::schedule`. + Self::schedule_runnable(&self.state, runnable); + task } @@ -219,7 +223,11 @@ impl StaticExecutor { .propagate_panic(true) .spawn_unchecked(|()| future, self.schedule()) }; - runnable.schedule(); + + // `Runnable::schedule` has an extra clone/drop of the Waker, which can + // be skipped by directly scheduling instead of calling `Runnable::schedule`. + Self::schedule_runnable(&self.state, runnable); + task } @@ -294,11 +302,16 @@ impl StaticExecutor { let state: &'static State = &self.state; // TODO: If possible, push into the current local queue and notify the ticker. move |runnable| { - let result = state.queue.push(runnable); - debug_assert!(result.is_ok()); // Since we use unbounded queue, push will never fail. - state.notify(); + Self::schedule_runnable(state, runnable); } } + + #[inline] + fn schedule_runnable(state: &'static State, runnable: Runnable) { + let result = state.queue.push(runnable); + debug_assert!(result.is_ok()); // Since we use unbounded queue, push will never fail. + state.notify(); + } } impl Default for StaticExecutor { @@ -375,7 +388,11 @@ impl StaticLocalExecutor { let (runnable, task) = Builder::new() .propagate_panic(true) .spawn_local(|()| future, self.schedule()); - runnable.schedule(); + + // `Runnable::schedule` has an extra clone/drop of the Waker, which can + // be skipped by directly scheduling instead of calling `Runnable::schedule`. + Self::schedule_runnable(&self.state, runnable); + task } @@ -408,7 +425,11 @@ impl StaticLocalExecutor { .propagate_panic(true) .spawn_unchecked(|()| future, self.schedule()) }; - runnable.schedule(); + + // `Runnable::schedule` has an extra clone/drop of the Waker, which can + // be skipped by directly scheduling instead of calling `Runnable::schedule`. + Self::schedule_runnable(&self.state, runnable); + task } @@ -480,11 +501,16 @@ impl StaticLocalExecutor { let state: &'static State = &self.state; // TODO: If possible, push into the current local queue and notify the ticker. move |runnable| { - let result = state.queue.push(runnable); - debug_assert!(result.is_ok()); // Since we use unbounded queue, push will never fail. - state.notify(); + Self::schedule_runnable(state, runnable); } } + + #[inline] + fn schedule_runnable(state: &'static State, runnable: Runnable) { + let result = state.queue.push(runnable); + debug_assert!(result.is_ok()); // Since we use unbounded queue, push will never fail. + state.notify(); + } } impl Default for StaticLocalExecutor {