何时在不同线程上安排“.await”调用 - 以及 tokio 任务何时在线程之间移动

Dan*_*iel 2 rust rust-tokio

我想了解 Rust 中 tokio 的 async/await 线程模型。我特别想知道 async/await 何时会导致代码在不同线程上执行。

我观察到,在带async fn main注释的#[tokio::main](创建多线程运行时)中运行 async/await/join 代码会在同一线程中执行所有代码。在我开始通过 执行代码之前,我没有看到其他线程被使用tokio::spawn

一些相关文档

任务是调度程序管理的执行单元。生成任务会将其提交给 Tokio 调度程序,然后调度程序确保该任务在有工作要做时执行。生成的任务可以在生成它的同一线程上执行,也可以在不同的运行时线程上执行。任务生成后还可以在线程之间移动。(强调我的)

这表示生成的单个 tokio 任务可以在执行期间在线程之间移动。什么时候会发生这种情况?

还有block_on运行#[tokio::main]函数体的文档

这会在当前线程上运行给定的 future,阻塞直到完成,并产生其解析结果。future 内部产生的任何任务或计时器都将在运行时执行。

这可以理解为除非产生新的任务或计时器,否则给定未来的代码将全部在同一线程上运行。这是我观察到的。

异步 rust 代码是否会在.await连接调用中同时(但不是并行)进行 future,并且仅在tokio::spawn使用时安排在不同的线程上?

文档似乎另有说明,如果是这样,如何决定将执行转移到新线程?

Mas*_*inn 5

在我开始通过 tokio::spawn 执行代码之前,我没有看到其他线程被使用。

那是因为他们不这样做,未来不是调度的单位,只有任务才是。

这表示生成的单个 tokio 任务可以在执行期间在线程之间移动。什么时候会发生这种情况?

这需要稍微回顾一下:多线程运行时意味着 tokio 有多个调度程序,每个线程一个。每个线程都有一个本地队列,以及一个用于整个运行时的附加全局共享队列。

默认情况下,如果任务是从async代码生成的,则该任务会在当前调度程序的队列中排队。如果本地队列已满或者任务是从运行时外部创建的(例如通过Runtime::block_on),则将其添加到共享队列中。

当调度程序没有任务运行时,它会检查其本地队列。

如果其本地队列为空或没有任务准备就绪,则它会尝试从同级队列窃取任务。这就是任务可以在线程之间移动的时候。

  • 不,任何当前未运行的任务都可能被窃取,这就是您无法在“.await”点上保留非“发送”项目的全部原因。 (2认同)