Poll from an async method

Hi

I am using tokio runtime v1.40, and I am implementing tokio::io::AsyncRead trait as below

pub struct MyStruct {}

impl MyStruct {

    async fn wait_one(&mut self) -> bool {
        // simulate some async logic
        tokio::time::sleep(Duration::from_millis(100)).await
        true
    }

}


impl tokio::io::AsyncRead for MyStruct {
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut std::task::Context<'_>,
        buf: &mut tokio::io::ReadBuf<'_>,
    ) -> Poll<std::io::Result<()>> {


        let mut future = Box::pin(self.wait_one());

        match Pin::new(&mut future).poll(cx) {
            Poll::Ready(success) => {
                if !success {
                    return Poll::Ready(Ok(()));
                }
            }
            Poll::Pending => {
                cx.waker().wake_by_ref();  // <-- why this line is needed
                return Poll::Pending;
            }
        }

        Poll::Ready(Ok(()))
    }
}

So, within my AsyncRead implementation, I want to call an async method wait_one. it is just a timer to simplify the question.

If cx.waker().wake_by_ref() line is removed, then after Poll::Pending is returned poll_read will never be fired again.

So I have to add cx.waker().wake_by_ref() in order to make poll_read be fired again.

I thought the future returned from wait_one should automatically register waker but that is not true.

Is cx.waker().wake_by_ref() efficient enough? could there be a better approach?

Thanks in advance

It does, But then you immediately drop future, and that de-registers the waker. In order for the wait_one() future to complete, you must poll it to completion, that is, poll the same future until it returns Poll::Ready. Not create a new one on every poll.

You'll need to add a field to MyStruct to store the future, and change wait_one() to not capture an &mut self borrow.

By doing that, you’re creating a spin loop, aka busy wait: any async task that calls your poll_read() will be polled again immediately. So, you will be occupying one CPU core with useless computation. Not efficient.

2 Likes

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.