Async - What is the point of polling?

Hey there,

I'm following the tokio tutorial about implementig Future myself, it got me wondering, if a Future is suposed to wake itself when its ready, why poll at all ? Couldn't it be assumed to be pending by default until it calls wake ?

Was it done this way to suport other types of async implementations ?

1 Like

After the runtime gets a notification that the Future is ready to do more work, it has to at some later point tell the Future to continue doing work. The poll call is how you tell a Future to continue doing work.

1 Like

Huh, It seemed to me the future should return Poll::Ready when its done working. Now Im confused :sweat_smile:

Yeah, I just edited my response because the terminology is a bit confusing. A waker tells the runtime that the Future is "ready to continue work" whereas Poll::Ready means "the Future is done working, the answer is ready".

I guess whats really confusing me is why would a future call wake when its not ready. I assume that some work is hapening on the background, the runtime "forgets" about the future until it calls wake, the future should wait until the work is done or goes wrong before calling wake, what would be the case to awake just to say you're not done yet ?

Here is an example:

async fn foo() {
    println!("A");
    tokio::time::sleep(Duration::from_secs(1)).await;
    println!("B");
    tokio::time::sleep(Duration::from_secs(1)).await;
    println!("C");
}

When the future is first polled, it will print "A", schedule a waker 1 second later, and return Poll::Pending.

1 second later the waker triggers. The runtime polls the same future again. It prints "B", schedules another waker and again returns Poll::Pending.

1 second later the waker triggers, the runtime polls the future again which prints "C" and returns Poll::Ready.

4 Likes

Another way to think about this is in terms of nested futures. A low-level future ( for example, one that says a network socket has more data available) will generally be the one that actually triggers the waker, and what really should happen is that control returns to the parent async block so that it can do something with the new data. For various technical reasons, that's tricky to do directly - instead, the top level task is polled so that it can work its way through all of the futures that it's waiting on until it finds the one that has new data.

4 Likes

Correction - it would return Poll::Pending, if it awaited sleeps.

1 Like

Ah yes, corrected, thanks. Implicit drop on ; strikes again. An "unused" warning was there but I ignored "unused" warnings in my example code because the function wasn't used on purpose.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.