Poll Future with zero-length timeout


My question is specific to tokio, but part of it applies to other runtimes. I'm piping data from a reader to a channel in small chunks, and I want to check for user input (from another channel) between each chunk.

What I really want is mpsc::UnboundedReceiver::try_recv, but it was removed. Apparently, I could use FutureExt::now_or_never, but I've been using this:

if let Ok(Some(cmd)) = timeout(Duration::from_millis(0), self.rx.recv()).await
    // process cmd

Is that going to do what I want? I haven't had any problems using it, but I also wouldn't notice a temporarily missed cmd in this context.

Aside from the missed message bug, I'm wondering if a zero-length timeout will always result in queued Futures being polled. Is that an idiomatic way to peek into the runtime from an async context?

Yes, it behaves almost the exact same as now_or_never does. Due to Tokio's coop it's actually now_or_never will sometimes spuriously return None, which you can prevent with tokio::task::unconstrained: unconstrained(self.rx.recv()).now_or_never().

As far as I can tell from the source this is the case, but you should be using yield_now.

Thanks for the info. I was looking at the source code to the Tokio coop system the other day, so it's interesting to see this connection.

I might have confused myself by asking two questions in one thread, so I'll state my understanding for clarification. It sounds like I should generally call yield_now when I want to defer to the runtime to let other tasks run. However, in my particular case, I want to poll the status of the recv() future without waiting for input, so I need to use unconstrained(self.rx.recv()).now_or_never().

Does that sound right?

Yes, unconstrained(self.rx.recv()).now_or_never() is the right way to try_recv. In fact, I added this to the issue.

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.