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

Rust中Future需await才执行,为何未await的tokio::spawn仍运行?

Rust异步执行现象底层原因

首先纠正一个认知边界:Future只有被await才会执行的结论,仅适用于没有被提交到异步运行时调度队列的普通Future。一旦调用tokio::task::spawn,执行逻辑就会发生本质变化,两个异常场景的具体原因如下:

场景1:未await JoinHandle仍能输出第二条打印

核心原因有两点:

  • task::spawn的本质是把传入的async块(即一个Future实例)直接提交给Tokio运行时的全局调度队列,JoinHandle只是用来获取任务返回值、感知任务状态的句柄,不是任务执行的开关。只要任务被提交到运行时,不需要主动await JoinHandle,运行时的工作线程有空就会主动轮询、调度这个任务执行,这是spawn生成的托管任务和普通惰性Future的核心区别。
  • 你在spawn的async块中写produce_event(500)时没有加.await,这行代码只会临时创建一个produce_event返回的Future实例,随即就会被丢弃,produce_event函数体内的逻辑一行都不会执行。整个spawn的async块中不存在任何会让出执行权的.await点,当运行时第一次轮询到这个任务时,会同步执行完块内所有逻辑,直接走到println!("Event produced at {}", seconds)完成打印,整个过程没有任何等待,执行速度极快,哪怕main函数即将退出,也大概率能在进程终止前跑完这段同步逻辑。

场景2:给produce_event(500)加.await后仅输出第一条打印

核心原因是任务执行到休眠点就被运行时挂起,还没等唤醒执行后续逻辑,整个进程就已经退出了:

  • 加上.await后,spawn的任务被运行时第一次轮询时,会真正进入produce_event函数执行,首先打印出第一条waiting 500的日志。
  • 紧接着代码执行到time::sleep(...).await,此时任务会立刻让出执行权,通知运行时:"500纳秒后再唤醒我继续执行",任务本身被挂起等待。
  • 你的f函数只是把spawn生成的JoinHandle存在了局部Vec中,从来没有await这些JoinHandle等待任务完成,f函数在提交完所有spawn任务后就会直接返回。main函数中通过FuturesUnordered等待所有f执行完成后,就会直接终止main函数、关闭Tokio运行时,所有未执行完成的spawn任务会被直接销毁。
  • 500纳秒的休眠时间极短,但任务被休眠到期唤醒、重新调度到工作线程执行的开销,远大于进程直接退出的速度,因此挂起的任务根本没机会执行到后续的第二条打印逻辑,进程就已经终止了。

补充说明:你提到的末尾等待所有Future执行完成后两条日志都正常输出的现象,本质是因为await JoinHandle会把当前执行流程卡住,直到spawn的任务被唤醒、执行完所有逻辑,给任务留足了完整执行的时间,不会被运行时提前销毁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:15:38