You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust仅用async/.await无线程时为何同步执行及如何实现真正异步

Rust async/await 执行顺序问题解析

参考官方示例

以下为Rust官方文档给出的示例:

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

官方文档对该示例的说明:

本示例中必须先学会歌曲才能唱歌,但学歌、唱歌的全过程可与跳舞操作同时执行。

测试复现与问题

针对上述逻辑编写测试代码验证:

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

运行后发现所有async函数表现为同步执行,实际输出:

learn_song
sing_song
dance
learn_song
sing_song

预期的异步交错执行输出类似:

learn_song
dance
learn_song
sing_song
sing_song

即便增加learn_and_sing的调用次数,输出仍然保持同步执行顺序。

核心问题:出现该现象的原因是什么?仅使用async/.await、不依赖多线程是否能够实现真正的异步?

问题解答

  • 首先明确Rust单线程async的调度规则:采用协作式调度,执行器只会在任务碰到.await点、主动声明自身需要等待、让出执行权的时候,才会切换运行其他就绪任务,不存在强制抢占式的任务切换。
  • 测试代码表现为同步执行的核心原因:代码中使用的std::thread::sleep是同步阻塞调用,它会直接占满当前线程1秒,这段时间代码不会走到任何.await让出点,执行器完全没有机会调度dance或者另一个learn_and_sing任务,自然呈现顺序执行效果。如果要实现等待时的任务切换,需要使用异步运行时提供的异步sleep实现,这类异步等待函数在计时期间会主动把执行权交还给执行器,其他任务就能在等待间隙被调度运行。

单线程无多线程是否可以实现真正的异步?

完全可以。
异步并发的核心从来不是多线程并行,而是在等待不需要占用CPU的操作(比如网络IO、磁盘IO、定时等待)时,主动让出CPU资源处理其他就绪任务,避免CPU空等浪费资源。
比如单线程异步模型下同时发起3个HTTP请求,在等待第一个请求的网络响应返回的空窗期,完全可以切换去处理第二个、第三个请求的发送、响应解析逻辑,全程仅使用一个线程,但总耗时远低于同步顺序执行3个请求的耗时,这就是实打实的异步并发能力。
测试中没有看到交错执行,本质是误用了同步阻塞调用占住线程不释放,和async/await本身的能力无关。


内容的提问来源于stack exchange,提问作者Yoskutik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:48:42