Rust in Everything
基于 embassy-executor 0.10.0

动手

前面各部分读的是 embassy 的源码。这一部分反过来:不依赖 embassy,只用 core、critical-section 和 cortex-m,把定时器主线和跨任务主线需要的那几样东西自己写一遍。写完之后在 std 和 QEMU 上跑同一对任务,再把同样的任务放到 embassy 上,比体积和 poll 次数。

  1. 写一个迷你执行器:库 474 行代码。任务放在定长的字节格子里,执行器只记一个类型擦除的 poll_fn,future 放不下是单态化时的编译错误,cargo check 看不到;运行队列是一个 u32 位图,一条 fetch_or 同时去重和决定要不要 SEV,批内按槽号出队;waker 是格子头指针加一张静态 vtable;时钟每毫秒 tick 一次,定时器表按到期时刻排序,只看表头。生产者、消费者经容量为 1 的 channel 通信,日志在 std、QEMU 和 embassy 上完全相同;同一 tick 两个任务同时到期时,mini 先跑槽号小的、embassy 先跑先登记的,生产者因此多 poll 一次(11 对 10)。QEMU 上 mini 和 embassy 的 .text 只差 100 字节,只换执行器差 76 字节;rotate 拉进的 1410 字节 memmove、把 future 当参数传进 async fn 后大小翻倍,都比执行器本身的差别大。最后一张表列出 embassy 多出来的东西(按任务定大小的池、原地构造、不限任务数的队列、可替换的时间驱动、InterruptExecutor、调度策略)和讲它们的页。
flowchart TB
  slot["任务槽"] --> mask["位图运行队列"]
  mask --> waker["手写 waker"]
  clock["时钟 定时器表"] --> waker
  chan["Channel"] --> waker
  waker --> std["std 条件变量"]
  waker --> qemu["QEMU WFE"]
  qemu --> cmp["和 embassy 比"]

💬 关联讨论

发起讨论
加载中...