Rust in Everything
基于 tokio-metrics 0.5.2

任务指标

这一部分是本卷的重点,讲任务主线。代码全在 src/task.rs 里:3 673 行中三分之二是文档注释,真正的算法只有 instrument_poll 和 State::on_wake 两个函数,加起来 170 行。难的不是代码,而是这几个时间戳到底在量什么:哪段等待算「空闲」、哪段算「排队」,和 tokio 自己的调度对不对得上。

  1. Instrumented 与 instrument_poll:instrument 时记下的东西;Instrumented 的四个字段;instrument_poll 逐段走一遍:首次 poll 延迟从 instrument() 被调用算起,一次 poll 取三次 Instant::now()、做十来次 SeqCst 原子操作;Stream 只给默认的 Instrumented<T, TaskMonitor> 实现。
  2. 包装 waker:空闲与排队怎么算:State 实现 ArcWake,on_wake 用 compare_exchange(0, now) 只记第一次唤醒;四个实验:两次唤醒、poll 里唤醒自己、yield_now、嵌套的 Instrumented,各自的时间落进哪一列。
  3. TaskMetrics 与派生指标:RawMetrics 的原子计数器怎么变成 19 个字段;没有单独的 poll 总数;在途数;最大空闲的两个原子变量;derived_metrics! 宏和 10 个派生指标,均值除以 0 得 0、两个比率除以 0 得 NaN;两个阈值。
  4. TaskMonitorCore 与 FutureMonitor:0.4.9 拆出不带 Arc 的 TaskMonitorCore,const fn 构造,可以放进 static;0.5.2 新增 FutureMonitor,一个 future 一份指标,排队时间要外层任务先打开 publish_scheduling_delay,借线程局部变量传进来。
flowchart TB
  inst["instrument:包一层"] --> poll["instrument_poll:三个时间戳"]
  poll --> waker["包装 waker:记唤醒时刻"]
  waker --> poll
  poll --> raw["RawMetrics:一组 AtomicU64"]
  raw --> tm["TaskMetrics:19 个字段"]
  tm --> derived["10 个派生指标"]
  inst --> core["TaskMonitorCore:可放进 static"]
  inst --> fm["FutureMonitor:一个 future 一份"]

第 1、2 章是全卷的地基:后面的运行时指标只是读 tokio 的计数器,而任务指标的每个字段,都可以对照这两章里的三个时间戳来理解它量的是哪一段。

💬 关联讨论

发起讨论
加载中...