1

I'm trying to call an async function inside non-async context, and I'm having a really hard time with it.

Channels have been far easier to use for me - it's pretty simple and intuitive.

recv means block the thread until you receive something.

try_recv means see if something's there, otherwise error out.

recv_timeout means try for a certain amount of milliseconds, and then error out if nothing's there after the timeout.

I've been looking all over in the documentation of std::future::Future, but I don't see any way to do something similar. None of the functions that I've tried are simple solutions, and they all either take or give weird results that require even more unwrapping.

Anime Weeb
  • 11
  • 1
  • 1
    *"I'm trying to call an async function inside a non-async context"* - you'll at minimum need an executor to drive the Future. See: [How do I synchronously return a value calculated in an asynchronous Future in stable Rust?](https://stackoverflow.com/q/52521201) – kmdreko Jul 07 '21 at 04:16
  • 1
    This question is pretty vague. Great questions usually include references to docs/resources you have looked at and a minimal example of the code you would like to have working. – Ultrasaurus Jul 07 '21 at 19:00

1 Answers1

1

The Future trait in the standard library is very rudimentary and provides a stable foundation for others to build on.

Async runtimes (such as tokio, async-std, smol) include combinators that can take a future and turn it into another future. The tokio library has one such combinator called timeout.

Here is an example (playground link), which times out after 1 second while attempting to receive on a oneshot channel.

use std::time::Duration;
use tokio::{runtime::Runtime, sync::oneshot, time::{timeout, error::Elapsed}};

fn main() {

    // Create a oneshot channel, which also implements `Future`, we can use it as an example.
    let (_tx, rx) = oneshot::channel::<()>();

    // Create a new tokio runtime, if you already have an async environment, 
    // you probably want to use tokio::spawn instead in order to re-use the existing runtime.
    let rt = Runtime::new().unwrap();

    // block_on is a function on the runtime which makes the current thread poll the future
    // until it has completed. async move { } creates an async block, which implements `Future`
    let output: Result<_, Elapsed> = rt.block_on(async move {
        // The timeout function returns another future, which outputs a `Result<T, Elapsed>`. If the
        // future times out, the `Elapsed` error is returned.
        timeout(Duration::from_secs(1), rx).await
    });

    println!("{:?}", output);
}

Mathieu Rene
  • 924
  • 5
  • 11