When will a Future return Pending?

In the following code , I want line A matched, but I found I can do nothing in ablock to make it true.


fn main() {
  let ablock = async {
    println!("async block");
    async {
      println!("nested");
    }.await;
  };
  poll(ablock);
}

struct MyWaker;
impl Wake for MyWaker {
  fn wake(self: Arc<Self>) {
    println!("wake");
  }
}

fn poll<T>(fut:impl Future<Output=T>)->T {
  let waker = Arc::new(MyWaker).into();
  let mut cx = Context::from_waker(&waker);
  let mut fut = Box::pin(fut);
  loop {
   match fut.as_mut().poll(&mut cx) {
     Poll::Ready(x) => return x,
     Poll::Pending => println!("Pending"), // A
   }
  }
}

You’d need to .await a future in ablock that actually does some asynchronous work, or that’s manually implemented to be able to return pending. With async blocks alone, you won’t encounter pending futures.

Yeah, it only returns pending if it hits an operation that can't immediately complete. Consider adding a call to tokio::task::yield_now.

You can actually read the implementation of that function @alice mentioned to see how a simple manual implementation of a (sensible) Future that can return pending (without doing work / interacting with a runtime) looks like.

got it

struct MyFuture;
impl Future for MyFuture {
  type Output=u8;
  fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
    Poll::Pending
  }
}

I'm overthinking things.

1 Like

One could question the practical utility of a future that keeps pending indefinitely, but – sure – that’s also an example of a Future that can return Pending.

An improved version :blush:

struct MyFuture(u8);
impl Future for MyFuture {
  type Output=u8;
  fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
    self.0 -= 1;
    if self.0>0 {
      Poll::Pending  
    } else {
      Poll::Ready(self.0)
    }    
  }
}
1 Like

Note that a smart executor won't poll a future again until it's been told to, so you might need to do an immediate cx.waker().wake_by_ref() when returning Poll::Pending otherwise MyFuture will never complete.

1 Like

For more details on how executors work, etc, this video is quite informative

1 Like

thank you , just in time I am wondering the role of Wake trait.

Consider reading Async in depth | Tokio - An asynchronous Rust runtime

1 Like

the following code help me a lot , I guess #[tokio::main] will transform the unusual main to an ordinary main and poll the unusual main.

#[tokio::main]
async fn main() {
    let what_is_this = my_async_fn();
    what_is_this.await;
}

You can see exactly what #[tokio::main] does by viewing its documentation.

yes it is. very handy , save many lines of code. :heart_eyes:

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.