Created
January 24, 2019 00:58
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![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