Anunaki
Anunaki

Reputation: 881

How to sleep in Future::poll()?

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

Upvotes: 0

Views: 202

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 70860

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.

Upvotes: 2

Related Questions