tokio 怎么把任务分给工作线程?一个任务会固定在一个线程上吗?一个不 await 的计算会拖垮什么?这篇用 4 个小程序观察 tokio 调度的真实行为,再看 spawn_blocking 怎么避开这些问题。
线程 ThreadId(2) 完成了 292 个任务
线程 ThreadId(3) 完成了 291 个任务
线程 ThreadId(4) 完成了 173 个任务
线程 ThreadId(5) 完成了 244 个任务
共 4 个工作线程参与手写执行器见Async Runtime 做了什么。
16 个任务里有 12 个在运行过程中换过工作线程(同一个任务的多次 poll 不一定在同一线程)
[ 0 ms] 开始 150 ms 的纯 CPU 计算(没有 await) [150 ms] 计算结束 [150 ms] ticker 第 1 次(期望每 20 ms 一次) [190 ms] ticker 第 2 次(期望每 20 ms 一次) [220 ms] ticker 第 3 次(期望每 20 ms 一次) [250 ms] ticker 第 4 次(期望每 20 ms 一次) [270 ms] ticker 第 5 次(期望每 20 ms 一次)
更多见阻塞代码混入异步任务。
[ 0 ms] 开始 150 ms 的纯 CPU 计算(没有 await) [ 20 ms] ticker 第 1 次 [ 50 ms] ticker 第 2 次 [ 70 ms] ticker 第 3 次 [100 ms] ticker 第 4 次 [120 ms] ticker 第 5 次 [150 ms] 计算结束
[ 20 ms] ticker 第 1 次 [ 50 ms] ticker 第 2 次 [ 70 ms] ticker 第 3 次 [100 ms] ticker 第 4 次 [120 ms] ticker 第 5 次 [150 ms] 阻塞任务在线程 ThreadId(2) 上完成(不是运行时线程 ThreadId(1)),ticker 全程正常