Skip to content

Instantly share code, notes, and snippets.

@d0nutptr
Created January 24, 2019 00:58
Show Gist options
  • Save d0nutptr/c39f9ce923e9c74164383d522378131e to your computer and use it in GitHub Desktop.
Save d0nutptr/c39f9ce923e9c74164383d522378131e to your computer and use it in GitHub Desktop.
How to process multiple async calls concurrently in rust. I left comments where I made mistakes initially so I don't mess this up again.
#![feature(await_macro, async_await, futures_api)]
extern crate futures;
#[macro_use]
extern crate tokio;
extern crate tokio_async_await;
use tokio::prelude::*;
use tokio::runtime::Runtime;
use tokio_async_await::compat::backward;
fn main() {
let mut data = Vec::new();
data.push("Hello".to_string());
data.push("this".to_string());
data.push("is".to_string());
data.push("d0nut".to_string());
// It appears that you can't get a result from an `async` function in your non-async code like you can using traditional futures
// Example:: let result = runtime.block_on(...);
// However, you can get a result if you convert the new future to an old one (`backward::Compat::new()`)
// Example:: let result = runtime.block_on(backward::Compat::new(<async call>));
// Make sure the async call returns a `Result` though!
// Print using result from reactor
print_message(data.clone());
println!("\n======================\n");
// Print using await
tokio::run_async(async_print_message(data.clone()));
println!("\nDone!");
}
fn print_message(data: Vec<String>) {
let mut runtime = Runtime::new().unwrap();
let result = runtime.block_on(future::join_all(process_message(data))).unwrap();
for item in result {
println!("Old: {}", item);
}
}
// If you want to use `await!` the current calling function must also be `async`
// Otherwise, you'll get a vague error message about a generator and yield call
async fn async_print_message(data: Vec<String>) {
let result = await!(future::join_all(process_message(data))).unwrap();
for item in result {
println!("New: {}", item);
}
}
// This wasn't obvious to me, but make sure to specify the `Item` and `Error` type
// Otherwise, the Future won't be `Send` which is needed.
fn process_message(data: Vec<String>) -> Vec<impl Future<Item=String, Error=()>> {
data.into_iter().map(move |message| {
// converts a `std::Future` to `futures::Future`. Necessary to use `join_all`
backward::Compat::new(capitalize(message))
}).collect()
}
// Remember that to convert `std::Future` to `futures::Future` you need to use a Result Type
async fn capitalize(message: String) -> Result<String, ()> {
// Sleep length of the message then return capitalized version of message
await!(sleep(message.len() as u64));
Ok(message.to_uppercase())
}
// Taken from https://jsdw.me/posts/rust-asyncawait-preview/
async fn sleep(n: u64) {
use tokio::timer::Delay;
use std::time::{Duration, Instant};
await!(Delay::new(Instant::now() + Duration::from_secs(n))).unwrap();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment