Home > Mobile >  Rust: async is not concurent
Rust: async is not concurent

Time:07-04

Here's the example from the Rust book.

async fn learn_and_sing() {
    // Wait until the song has been learned before singing it.
    // We use `.await` here rather than `block_on` to prevent blocking the
    // thread, which makes it possible to `dance` at the same time.
    let song = learn_song().await;
    sing_song(song).await;
}

async fn async_main() {
    let f1 = learn_and_sing();
    let f2 = dance();

    // `join!` is like `.await` but can wait for multiple futures concurrently.
    // If we're temporarily blocked in the `learn_and_sing` future, the `dance`
    // future will take over the current thread. If `dance` becomes blocked,
    // `learn_and_sing` can take back over. If both futures are blocked, then
    // `async_main` is blocked and will yield to the executor.
    futures::join!(f1, f2);
}

fn main() {
    block_on(async_main());
}

And it's says

In this example, learning the song must happen before singing the song, but both learning and singing can happen at the same time as dancing.

But I can't get this point. I wrote a short code in Rust

async fn learn_song() -> &'static str {
    println!("learn_song");
    "some song"
}

#[allow(unused_variables)]
async fn sing_song(song: &str) {
    println!("sing_song");
}

async fn dance() {
    println!("dance");
}

async fn learn_and_sing() {
    let song = learn_song().await;
    std::thread::sleep(std::time::Duration::from_secs(1));
    sing_song(song).await;
}

async fn async_main() {
    let f1 = learn_and_sing();
    let f2 = dance();
    let f3 = learn_and_sing();

    futures::join!(f1, f2, f3);
}

fn main() {
    futures::executor::block_on(async_main());
}

And it seems like all the async functions in the async_main executed synchronously.

The output is

learn_song
sing_song
dance
learn_song
sing_song

If they run asynchronously, I would expect to get something like this in my output

learn_song
dance
learn_song
sing_song
sing_song

If I add an extra call of learn_and_sing it would steel be printed like in a synchronous function.

The question Why so? Is it possible to make a real async using only async/.await and no threads?

CodePudding user response:

Like tkausl's comment states, std::thread::sleep makes the whole thread sleep, which prevents any code on the thread from executing during the sleeping duration. You could use async_std::task::sleep in this situation, as it is an asynchronous version of the sleep function.

async fn learn_song() -> &'static str {
    println!("learn_song");
    "some song"
}

#[allow(unused_variables)]
async fn sing_song(song: &str) {
    println!("sing_song");
}

async fn dance() {
    println!("dance");
}

async fn learn_and_sing() {
    let song = learn_song().await;
    async_std::task::sleep(std::time::Duration::from_secs(1)).await;
    sing_song(song).await;
}

#[async_std::main] 
async fn main() {
    let f1 = learn_and_sing();
    let f2 = dance();
    let f3 = learn_and_sing();

    futures::join!(f1, f2, f3);
}
  • Related