diff --git a/src/task/mod.rs b/src/task/mod.rs index 1f172c1..578a545 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -49,6 +49,13 @@ mod worker; pub(crate) mod blocking; +cfg_if::cfg_if! { + if #[cfg(any(feature = "unstable", feature = "docs"))] { + mod yield_now; + pub use yield_now::yield_now; + } +} + /// Spawns a blocking task. /// /// The task will be spawned onto a thread pool specifically dedicated to blocking tasks. This diff --git a/src/task/yield_now.rs b/src/task/yield_now.rs new file mode 100644 index 0000000..6f59638 --- /dev/null +++ b/src/task/yield_now.rs @@ -0,0 +1,53 @@ +use crate::future::Future; +use crate::task::{Context, Poll}; + +use std::pin::Pin; + +/// Cooperatively gives up a timeslice to the task scheduler. +/// +/// Calling this function will move the currently executing future to the back +/// of the execution queue, making room for other futures to execute. This is +/// especially useful after running CPU-intensive operations inside a future. +/// +/// See also [`task::spawn_blocking`]. +/// +/// [`task::spawn_blocking`]: fn.spawn_blocking.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// # fn main() { async_std::task::block_on(async { +/// # +/// use async_std::task; +/// +/// task::yield_now().await; +/// # +/// # }) } +/// ``` +#[cfg(any(feature = "unstable", feature = "docs"))] +#[cfg_attr(feature = "docs", doc(cfg(unstable)))] +#[inline] +pub async fn yield_now() { + YieldNow(false).await +} + +struct YieldNow(bool); + +impl Future for YieldNow { + type Output = (); + + // The futures executor is implemented as a FIFO queue, so all this future + // does is re-schedule the future back to the end of the queue, giving room + // for other futures to progress. + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if !self.0 { + self.0 = true; + cx.waker().wake_by_ref(); + Poll::Pending + } else { + Poll::Ready(()) + } + } +}