EDIT: actually this was wishful thinking, since both functions would block the main thread. The functions need to be modified to "suspend" for this to be truly async.
My ideal language would be something like Kotlin suspend semantics, except ALL functions were implicitly "suspend" functions. If that's even possible...
let result = executor::block_on({
let one = async { do_something_useful_one() };
let two = async { do_something_useful_two() };
one.await + two.await
});
This code block doesn't actually work the way the Kotlin one does. Async functions are mere pull-based state machines, so both `one` and `two` will compute serially, without concurrency.
What you need is:
use futures::join;
let result = executor::block_on({
let one = async { do_something_useful_one() };
let two = async { do_something_useful_two() };
let (one, two) = join!(one, two);
one + two
});
I feel like this might be a common stumbling block and hope there will be a Clippy check for this or something.
Ah, thank you. I wasn't aware that the Kotlin syntax automatically raced `one` and `two`. I'm not sure how I feel about that, but I haven't thought deeply about it. My gut is kinda "meh".
In the spirit of getting it right, your code is missing an `await` and `join` is back to a function in alpha18. Here's the currently working (this time tested!) code:
#![feature(async_await)]
use futures::{executor, future}; // 0.3.0-alpha.18
fn main() {
let result = executor::block_on(async {
let one = async { do_something_useful_one() };
let two = async { do_something_useful_two() };
let (one, two) = future::join(one, two).await;
one + two
});
println!("{}", result);
}
fn do_something_useful_one() -> i32 { 1 }
fn do_something_useful_two() -> i32 { 2 }
It doesn't automatically race. The "async" block in Kotlin is an equivalent to "spawn" in Rust, and launches everything in it as a child task. However compared to Rusts spawn Kotlin makes use of structured concurrency - which means parent tasks wait for child tasks and if you cancel a parent task the child task will get notified. So it's meaning is definitely closer to the join() based solution you documented.
The sequential but still async version in Kotlin is simply
val result = runBlocking {
doSomethingUsefulOne() + doSomethingUsefulTwo()
}
Yes, one big push in Rust is that you get to have your high-level syntax with your low-level performance.
See the sibling comment [1] where I actually tested and ran the code, finally. ;-). I was unaware that Kotlin would race two `async` blocks, so we had to use the `join` combinator here.
EDIT: actually this was wishful thinking, since both functions would block the main thread. The functions need to be modified to "suspend" for this to be truly async.
My ideal language would be something like Kotlin suspend semantics, except ALL functions were implicitly "suspend" functions. If that's even possible...