I want to implement a Future that busy-waits on its completion.
According to this link, this is one option
impl Future for Delay {
type Output = &'static str;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>)
-> Poll<&'static str>
{
if Instant::now() >= self.when {
println!("Hello world");
Poll::Ready("done")
} else {
// Ignore this line for now.
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
What I am worried about is this future starving out other tasks. Is it guaranteed that if I call wake inside the Future that returns Pending, that this wake will execute as a last item after epol, timers, and any other wakes called before?
Is this the good way to implement busy-wait Future?
Related
I want to add sleep to avoid busy loop in Future::poll(), expect the finally effect is that runtime call poll() every second, the fifth second will return Poll::Ready(()).
According to my understanding, poll() is be called in first, this.sleeper.poll(cx) will return Poll::Pending immediately, cx.waker().wake_by_ref() will make current task to execute again immediately.
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use pin_project_lite::pin_project;
use std::time::{Duration, Instant};
pin_project! {
struct Delay {
when: Instant,
#[pin]
sleeper: tokio::time::Sleep,
}
}
impl Delay {
pub fn new(when: Instant) -> Self {
Self {
when,
sleeper: tokio::time::sleep(Duration::from_secs(1))
}
}
}
impl Future for Delay {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.when < Instant::now() {
Poll::Ready(())
} else {
let this = self.project();
// I want to add sleep to avoid busy loop.
this.sleeper.poll(cx);
// here will make CPU busy loop, uninterrupted call poll()
cx.waker().wake_by_ref();
// expect five "1", but will get many "1"
print!("1");
Poll::Pending
}
}
}
#[tokio::main]
async fn main() {
let when = Instant::now() + Duration::from_secs(5);
let delay1 = Delay::new(when);
delay1.await;
println!("Hello, world!");
}
Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=030fbade7a2f1e5df50c4774fc06fdf1
There are two problems here. First and simplest, when your future is delegating to another future in poll(), you do not need to call the waker at all — the other future will do that. In this case, the Sleeper takes care of getting the waker called at the right time, causing your future to be polled again.
Second, you're ignoring the return value of the sleeper.poll(). If it returns Poll::Ready, you need to make sure you don't poll it again — either do something else, or replace self.sleeper with a new sleep(). Polling a future again after it returned Poll::Ready is not meaningful, and has consequences left up to the future (often a panic).
finally, I resoved this problem by changing Sleep to Interval and call poll_tick().
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use pin_project_lite::pin_project;
use std::time::{Duration, Instant};
use tokio::time::Sleep;
pin_project! {
struct Delay {
when: Instant,
#[pin]
sleeper: tokio::time::Interval,
}
}
impl Delay {
pub fn new(when: Instant) -> Self {
Self {
when,
sleeper: tokio::time::interval(Duration::from_secs(1))
}
}
}
impl Future for Delay {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
println!("0");
if self.when < Instant::now() {
println!("1");
Poll::Ready(())
} else {
println!("2");
let this = unsafe {self.get_unchecked_mut()};
//let this = self.project();
this.sleeper.poll_tick(cx);
Poll::Pending
}
}
}
#[tokio::main]
async fn main() {
let when = Instant::now() + Duration::from_secs(5);
let delay1 = Delay::new(when);
delay1.await;
}
I want to sleep 1 second in poll(), but it gets stuck in Pending.
From what I understand, I pass it &mut cx and it should wake up the current task after 1 second.
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::{Duration};
struct MyDelay {}
impl Future for MyDelay {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
println!("poll");
let sleep = tokio::time::sleep(Duration::from_secs(1));
tokio::pin!(sleep);
sleep.poll(cx)
}
}
#[tokio::main]
async fn main() {
let delay = MyDelay{};
let a = delay.await;
dbg!(a);
}
Play url: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ed6c09df100f1140ddc85b2ae600ab93
Each time you poll you create a new Sleep future, and it starts from scratch.
Instead, you should store the Sleep inside your future. It is easy with pin-project-lite:
pin_project_lite::pin_project! {
struct MyDelay {
#[pin]
sleep: tokio::time::Sleep,
}
}
impl MyDelay {
fn new() -> Self {
Self {
sleep: tokio::time::sleep(Duration::from_secs(1)),
}
}
}
impl Future for MyDelay {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
println!("poll");
let this = self.project();
this.sleep.poll(cx)
}
}
Playground.
Note that the number of times this will be polled is not guaranteed, and may not be constant.
So I'm getting a Response from the reqwest crate and passing it to a HttpResponseBuilder from the actix_web create. However I've tried and failed to understand how to implement the Stream trait from the futures create on a custom struct to act as a middleman and copy the contents down to a file.
I've tried doing this so far, but I'm not sure what to put inside that poll_next function to make it all work.
struct FileCache {
stream: Box<dyn futures::Stream<Item = reqwest::Result<bytes::Bytes>>>,
}
impl FileCache {
fn new(stream: Box<dyn futures::Stream<Item = reqwest::Result<bytes::Bytes>>>) -> Self {
FileCache { stream }
}
}
impl Stream for FileCache {
type Item = reqwest::Result<bytes::Bytes>;
fn poll_next(
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Option<Self::Item>> {
}
}
This is possible but requires you to understand what pinning is and how to use it safely.
Basically, we just need to proxy to self.stream.poll_next(), but this method accepts Pin<&mut Self> (as you can see in your own implementation). Storing the box as Pin<Box<T>> instead of Box<T> will give us a way to obtain this Pin relatively easily, without requiring unsafe. Making this change is straightforward, since there is a From implementation allowing conversion of Box<T> to Pin<Box<T>> directly:
use std::pin::Pin;
use std::task::{Context, Poll};
use futures::Stream;
struct FileCache {
stream: Pin<Box<dyn Stream<Item = reqwest::Result<bytes::Bytes>>>>,
}
impl FileCache {
fn new(stream: Box<dyn Stream<Item = reqwest::Result<bytes::Bytes>>>) -> FileCache {
FileCache { stream: stream.into() }
}
}
Now we have to figure out how to go from Pin<&mut FileCache> to Pin<&mut dyn Stream<...>>. The correct incantation here is self.get_mut().stream.as_mut():
impl Stream for FileCache {
type Item = reqwest::Result<bytes::Bytes>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match self.get_mut().stream.as_mut().poll_next(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(v) => {
// Do what you need to do with v here.
Poll::Ready(v)
}
}
}
}
The catch is that poll_next isn't async and so you can't asynchronously wait for whatever you're doing with v. bytes::Bytes is atomically-refcounted, though, so you could clone the inner bytes::Bytes value and spawn a separate task on your executor, which is probably what you want to do anyway so that whoever is waiting for FileCache doesn't have to wait for that task to complete before using the data. So you'd do something like:
Poll::Ready(v) => {
if let Some(Ok(ref bytes)) = &v {
let bytes = bytes.clone();
spawn_new_task(async move {
// Do something with bytes
});
}
Poll::Ready(v)
}
Where spawn_new_task() is the function your executor provides, e.g. tokio::spawn().
Now that we can see what we're doing here, we can simplify this down and eliminate the match by pushing Poll::Ready into our pattern, and unconditionally returning whatever the inner poll_next() call did:
impl Stream for FileCache {
type Item = reqwest::Result<bytes::Bytes>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let r = self.get_mut().stream.as_mut().poll_next(cx);
if let Poll::Ready(Some(Ok(ref bytes))) = &r {
let bytes = bytes.clone();
spawn_new_task(async move {
// Do something with bytes
});
}
r
}
}
I'm willing to impl a simple Future counter, but smth goes decidedly wrong about it. Without any use of Context the following programme would just block forever;
use std::future::Future;
use std::task::{Poll, Context};
use std::pin::Pin;
use futures::executor::block_on;
struct MyStruct {
counter: u32
}
impl Future for MyStruct {
type Output = String;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.counter == 5 {
Poll::Ready(self.counter.to_string())
} else {
unsafe {
Pin::get_unchecked_mut(self).counter += 1;
}
// cx.waker().wake();
Poll::Pending
}
}
}
fn main() {
let ms = MyStruct{counter: 0};
block_on(ms);
}
I imagine that I have to postpone somehow a call of Waker, but it's not that straightforward. So I wonder, how to wake it in the most simple form?
You can call .wake_by_ref(). Waking the waker will tell the executor that is handling the Future to be .poll()'d again:
impl Future for MyStruct {
type Output = String;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.counter == 5 {
Poll::Ready(self.counter.to_string())
} else {
unsafe {
Pin::get_unchecked_mut(self).counter += 1;
}
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
So your implementation will always ask to be immediately re-polled. I'll note that this is logically no different than simply returning Poll::Ready("5".to_string()) on the first invocation since there's no asynchronous work being done here. Because of that, there's no reason for it to be a Future at all.
This question already has answers here:
How to implement a Future or Stream that polls an async fn?
(2 answers)
Closed 5 months ago.
How to implement Futures::poll the the following code that will call async method with full ownership to the self?
use anyhow::Error;
use futures::Future;
use futures::channel::oneshot;
use futures::task::{Context, Poll};
use std::pin::Pin;
struct MyLongTask {
rx: oneshot::Receiver<()>,
}
impl MyLongTask {
// The method and full ownership to `self` is important to keep!
async fn recv(mut self) -> Result<(), Error> {
self.rx.await.map_err(|_| Error::msg("can't recv"))
}
}
// TryFuture not necessary here
impl Future for MyLongTask {
type Output = Result<(), Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
todo!("how to `self.recv().await` here?")
}
}
fn main() { }
Playground if needed.
You can't call self.recv() inside poll firstly because it does not own self, and secondly because it is not async.
Future::poll is synchronous but must return quickly regardless of whether a return value is ready (that's the whole idea of Poll::Pending).
In your case you should simply delegate the poll to self.rx: (playground)
impl Future for MyLongTask {
type Output = Result<(), Error>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.rx).poll(cx) {
Poll::Ready(x) => Poll::Ready(x.map_err(|_| Error::msg("can't recv"))),
Poll::Pending => Poll::Pending,
}
}
}
Now instead of using task.recv().await, you can just do task.await.
I'd also suggest you either implement Future or provide the recv method.
Otherwise you could run into trouble later when you change one implementation and forget to change the other.