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
相关产品推荐
相关产品推荐

