Skip to content

Commit

Permalink
task: add consume_budget for cooperative scheduling
Browse files Browse the repository at this point in the history
For cpu-only computations that do not use any Tokio resources,
budgeting does not really kick in in order to yield and prevent
other tasks from starvation. The new mechanism - consume_budget,
performs a budget check, consumes a unit of it, and yields only
if the task exceeded the budget. That allows cpu-intenstive
computations to define points in the program which indicate that
some significant work was performed. It will yield only if the budget
is gone, which is a much better alternative to unconditional yielding,
which is a potentially heavy operation.
  • Loading branch information
psarna committed May 30, 2022
1 parent f6c0405 commit 114d845
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 0 deletions.
45 changes: 45 additions & 0 deletions tokio/src/task/consume_budget.rs
@@ -0,0 +1,45 @@
use std::task::Poll;

/// Consumes a unit of budget and returns the execution back to the Tokio
/// runtime *if* the task's coop budget was exhausted.
///
/// The task will only yield if its entire coop budget has been exhausted.
/// This function can can be used in order to insert optional yield points into long
/// computations that do not use Tokio resources like sockets or semaphores,
/// without redundantly yielding to the runtime each time.
///
/// **Note**: This is an [unstable API][unstable]. The public API of this type
/// may break in 1.x releases. See [the documentation on unstable
/// features][unstable] for details.
///
/// # Examples
///
/// Make sure that a function which returns a sum of (potentially lots of)
/// iterated values is cooperative.
///
/// ```
/// async fn sum_iterator(input: &mut impl std::iter::Iterator<Item=i64>) -> i64 {
/// let mut sum: i64 = 0;
/// while let Some(i) = input.next() {
/// sum += i;
/// tokio::task::consume_budget().await
/// }
/// sum
/// }
/// ```
/// [unstable]: crate#unstable-features
#[cfg_attr(docsrs, doc(cfg(feature = "rt")))]
pub async fn consume_budget() {
let mut status = Poll::Pending;

crate::future::poll_fn(move |cx| {
if status.is_ready() {
return status;
}
status = crate::coop::poll_proceed(cx).map(|restore| {
restore.made_progress();
});
status
})
.await
}
5 changes: 5 additions & 0 deletions tokio/src/task/mod.rs
Expand Up @@ -291,6 +291,11 @@ cfg_rt! {
mod yield_now;
pub use yield_now::yield_now;

cfg_unstable! {
mod consume_budget;
pub use consume_budget::consume_budget;
}

mod local;
pub use local::{spawn_local, LocalSet};

Expand Down

0 comments on commit 114d845

Please sign in to comment.