我想了解一下Rust中时雄的async/await线程模型。特别是我想知道async/await什么时候会导致代码在不同的线程上执行。
我所观察到的是,在一个用#[tokio::main]
注解的async fn main
中运行async/await/join代码(这会创建一个多线程运行时)会在同一个线程中执行所有代码。直到我开始通过tokio::spawn
执行代码,我才看到使用了额外的线程。
一些relevant docs。
任务是由调度程序管理的执行单元。生成任务时将其提交给时雄调度程序,然后该调度程序确保任务在有工作要做时执行。所产生的任务可以在与产生它的线程相同的线程上执行,或者它可以在不同的运行时线程上执行。任务生成后也可以在线程间移动。(重点是我的)
也就是说,生成的单个时雄任务可以在执行期间在线程之间移动。这是什么时候的事?
还有block_on
的文档,#[tokio::main]
在其中运行函数体
这将在当前线程上运行给定的future,阻塞直到它完成,并产生其解析结果。未来内部产生的任何任务或计时器都将在运行时执行。
这可以理解为,除非产生新的任务或计时器,否则给定未来的代码将在同一线程上运行。这是我观察到的。
是否异步rust代码将在.await
和join调用之间并发(但不是并行)进行future,并且仅在使用tokio::spawn
时在不同的线程上调度?
文档似乎另有说明,如果是这样的话,如何决定将执行转移到新线程?
1条答案
按热度按时间ep6jt1vc1#
直到我开始通过时雄::spawn执行代码,我才看到使用了额外的线程。
这是因为他们不这样做,future 不是调度的单位,只有 task 是。
也就是说,生成的单个时雄任务可以在执行期间在线程之间移动。这是什么时候的事?
这需要倒回一点:多线程运行时意味着时雄具有多个调度器,每个线程一个调度器。这些线程中的每一个都有一个 * 本地队列 *,加上一个额外的全局 * 共享队列 *,用于整个运行时。
默认情况下,如果任务是从
async
代码派生的,则该任务将在当前调度程序的队列中排队。如果本地队列已满 * 或 *,则从运行时外部创建任务(例如viaRuntime::block_on
),则将其改为添加到 * 共享队列 *。当调度程序没有任务运行时,它会检查其本地队列。
如果它的本地队列为空或没有任务准备就绪,则它会尝试从同级窃取任务。也就是说,任务可以在线程之间移动。