Tokio[1]的 task (一个 Future ) 里如果使用了阻塞调用,例如std::Mutex,会阻塞当前的 tokio-worker 线程,这个 worker 无法再执行其他 task。所以代码里如果不可避免的有(少量的)阻塞调用,就要为 runtime 启动更多的 worker 线程,保证存在没被阻塞的 worker 来执行待调度的 task,以避免整个 tokio runtime 完全 hang 住(有 task 但没 worker 运行它)。
但现实是,就算 worker 再多,tokio 也可能造成永久性的阻塞。
原因是 tokio 里的待执行 task 不是简单的放到一个 queue 里,除了 runtime 内共享的,可被每个 worker 消费的run_queue[2],每个 worker 还有一个自己的lifo_slot[3],只存储一个最后被放入的 task (目的是减小调度延迟)。lifo_slot只由它所属的 worker 使用,里面存储的 task 不能被其他 worker 执行。由于这个结构,构造 hang 住的方法是如图所示:
-
•Future f1 被 runtime-1 执行, 持有一个 async 的锁
m后,返回了Pending,这时它被调度到 worker-1 本地的lifo_slot。 -
•Future f2 在 runtime-1 执行后返回
Pending,被放入共享队列run_queue。 -
•Future f3 在 runtime-1 中执行, 它将一个任务
f4交给其他的 runtime 去完成(例如为了隔离网络IO和本地磁盘IO),使用block_on(f4)[4]的方式,等待执行结果返回。 -
• f4 中也需要锁
m,等待。
这时,f2 在共享队列run_queue中,可以被执行,但是 f1 在 worker-1 本地的lifo_slot里,只能由 worker-1 调度,但 worker-1 当前阻塞在 f3。于是等待关系形成了一个环:f4 → m(f1) → f3 → f4,hang 死任务达成。

审核编辑 :李倩
-
存储
+关注
关注
13文章
4692浏览量
89541 -
线程
+关注
关注
0文章
508浏览量
20753 -
Worker
+关注
关注
0文章
8浏览量
6680 -
Tokio
+关注
关注
0文章
12浏览量
231
原文标题:Tokio 中 hang 死所有 worker 的方法
文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
什么是Tokio模块 Channel?
鸿蒙原生应用开发-ArkTS语言基础类库多线程TaskPool和Worker的对比(三)
HarmonyOS NEXT 原生应用/元服务-ArkTS代码调试worker/taskpool调试
TaskPool和Worker的对比分析
面向对象嵌入式实时操作系统Worker1.0
normal worker_pool详细的创建过程代码分析
WasmEdge增加了Tokio支持
Tokio 模块的优雅停机机制
如何使用Tokio 和 Tracing模块构建异步的网络应用程序
如何使用 Tokio 模块的Channel
tokio模块channel中的使用场景和优缺点
Tokio 的基本用法
Channel模块的使用方法示例
鸿蒙语言基础类库:ohos.worker 启动一个Worker

Tokio中hang死所有worker的方法
评论