rustasync-awaitthread-sleep

Concurrent async/await with sleep


I would like to know if the answer to this rather old question about futures still applies to the more recent language constructs async/await. It seems to be so, since code below prints:

hello 
good bye 
hello

although the guide says

The futures::join macro makes it possible to wait for multiple different futures to complete while executing them all concurrently.

Clearly, it's a diversion of the expected behavior in many, many other asynchronous systems (node.js for example), with regard to sleep.

Any fundamental reason to be that way?

use std::time::Duration;
use std::thread;

async fn sayHiOne() {
    println!( " hello " );
    thread::sleep( Duration::from_millis( 3000 ) );
    println!( " good bye " );
} // ()

async fn sayHiTwo() {
    println!( " hello " );
} // ()

async fn mainAsync() {

    let fut1 = sayHiOne();

    let fut2 = sayHiTwo();

    futures::join!( fut1, fut2 );
} // ()

fn main() {
    block_on( mainAsync() );
} // ()

Addition: the behavior (I) expected with actual threads

fn main() {

    let fut1 = do_async( move || {
        println!( "hello" );
        thread::sleep( Duration::from_millis( 3000 ) );
        println!( "good bye" );
    });

    let fut2 = do_async( move || {
        println!( "hello" );
    });

    fut1();
    fut2();

}

use std::thread;
use std::time::Duration;
use std::sync::mpsc::channel;


fn do_async<TOut, TFun>( foo: TFun ) -> (impl FnOnce()-> TOut)
 where
    TOut: Send + Sync + 'static,
    TFun: FnOnce() -> TOut + Send + Sync + 'static
    
{

    let (sender, receiver) 
        = channel::< TOut >();

    let hand = thread::spawn(move || {
        sender.send( foo() ).unwrap(); 
    } );

    let f = move || -> TOut {
        let res = receiver.recv().unwrap();
        hand.join().unwrap();
        return res;
    };

    return f;
} // ()

Solution

  • Yes, it still applies. It fundamentally has to be that way because, like the linked answer says, each async function will be running on the same thread - std::thread::sleep knows nothing about async, and so will make the whole thread sleep.

    Nodejs (and JavaScript in general) is much more designed around async, so the language primitives and the language runtime are more async-aware in that way.