I've been using the proposed await!
and Future
features in nightly Rust, and overall, I really like the design. But I did run into one surprise: await!
may never return, and this has consequences I didn't fully understand. Let's take a look.
We're going to use Rust nightly-2019-02-08
, and tokio-async-await
. This is highly experimental code, and it will require us to convert back and forth between tokio::Future
and the proposed std::future::Future
.
You can find the full code on GitHub. We'll start by enabling the experimental features we'll need:
#![feature(await_macro,async_await,futures_api)]#[macro_use]externcratetokio_async_await;
Then we'll import some libraries, and declare two helper functions tokio_fut
and boxed_fut
, that make it easy to convert from std::future::Future
into tokio::Future
and into Box<tokio::Future<..>>
, respectively. You can look that code up on GitHub.
Next, we define a function delay
, which returns a Future
that waits for the specified number of milliseconds:
fndelay(millis:u64)->Delay{Delay::new(Instant::now()+Duration::from_millis(millis),)}
Canceling a Future
Now, we can define two tasks:
/// An asynchronous function that completes quickly.asyncfnquick_task()->Result<&'staticstr>{println!("START quick_task");await!(delay(10)).context("delay failed")?;println!("END quick_task");Ok("quick_task result")}/// An asynchronous function that completes very slowly.asyncfnslow_task()->Result<&'staticstr>{println!("START slow_task");await!(delay(10_000)).context("delay failed")?;println!("END slow_task");Ok("slow_task result")}
Here, quick_task
waits for 10 milliseconds, and slow_task
waits for 10,000 milliseconds. We can combine them using select_all
: