并发 async/await 与睡眠

Concurrent async/await with sleep

我想知道 关于 futures 的答案是否仍然适用于更新的语言结构 async/await。似乎是这样,因为下面的代码打印:

hello 
good bye 
hello

虽然the guide

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

显然,对于 sleep,它是许多其他异步系统(例如 node.js)中预期行为的转移。

这样做有什么根本原因吗?

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() );
} // ()

补充:实际线程的预期行为 (I)

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;
} // ()

是的,它仍然适用。它从根本上必须是那样的,因为就像链接的答案所说的那样,每个异步函数将在同一个线程上 运行 - std::thread::sleep 对异步一无所知,因此会使整个线程休眠。

Nodejs(通常 JavaScript)更多地围绕异步进行设计,因此语言原语和语言运行时更多 async-aware。

由于 standard/original thread::sleep 是阻塞的,结果是异步库提供了 async_std::task::sleep( ... ),这是睡眠的非阻塞版本。它与 .await(无括号)一起使用:

task::sleep::( Duration::from_millis( 1 ) ).await;

这个 sleepunstable 版本具有相同的效果:yield_now 在某种意义上它

moves the currently executing future to the back of the execution queue, making room for other futures to execute. This is especially useful after running CPU-intensive operations inside a future.

所以我猜,预期用途是在任务计划执行长时间工作时“友善地”在未来之间共享线程的使用。