Polling in new-era futures

Suppose I want an async fn that checks a condvar. This async fn gets polled, and ought to return a result with Some when ready. I am calling this from another function. What is the general syntax for returning a future in a poll-like style?

I think that as currently designed, async fn is only intended to be a tool for polling existing Future implementations (from tokio, hyper, etc).

If you want to implement the Future trait yourself by defining what happens when the future is polled and how completion is signalled to the runtime, then you still need to write down the impl Future explicitly.

In addition, note that Rust's async runtimes do not continuously poll the futures. The runtime polls them once, and if they are busy it waits for a readiness notification before polling them again. You can emulate continuous polling by sending such a readiness notification on every poll, but that is likely to be quite inefficient due to the underlying synchronization machinery.

In this particular case, you will probably end up facing the fact that CondVar is fundamentally an async-unfriendly blocking abstraction, and needing to set up a dedicated thread for blocking on it and signalling the async runtime when it does something.

The alternative would be to replace the CondVar with some kind of message queue that sends readiness notifications to the async runtime in a nonblocking way. In the new async design, Waker can play this role.

What do you want to use it for? Note that futures always need something to notify them when they're ready to continue, and a condvar won't notify the future.

Thank you everyone for your responses.

I was mistaken Hadrien, I meant "conditional variable" like a boolean. I want something like the below code, but I want to know the simplest way to do it without having to use someone else's library (lots of annoying compat issues and needing to go through cargo.toml's and switching out dependency versions to match in the current transition phase. I would rather just make my own)

fn main(){
    block_on(alert_in_2s(Instant::now().add(Duration::from_ms(2000))));
}

async fn alert_in_2s(instant_2s: Instant) -> bool {
    if Instant::now() < instant_2s {
        false
    } else {
        println!("done waiting");
        true
    }
}

If you wish to do it without using any libraries, you could do this.

Note that this can be done much more efficiently than starting a full thread for every sleeping future, and if you use a dependency like tokio, their timer will use that method.

use std::time::Instant;
use std::task::{Poll, Context};
use std::future::Future;
use std::pin::Pin;

struct WaitFuture {
    thread_started: bool,
    until: Instant,
}

impl Future for WaitFuture {
    type Output = ();
    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
        if self.until <= Instant::now() {
            Poll::Ready(())
        } else {
            if !self.thread_started {
                let wait = cx.waker().clone();
                let until = self.until;
                std::thread::spawn(move || {
                    let now = Instant::now();
                    if now < until {
                        std::thread::sleep(until - now);
                    }
                    wait.wake();
                });
                self.thread_started = true;
            }
            Poll::Pending
        }
    }
}
2 Likes