Rust in Everything
基于 tokio 1.54.1

用户层 API

前面几部分从运行时内部往外看:任务怎么分配、调度器怎么取任务、驱动怎么唤醒。这一部分反过来,从用户代码里最常见的几个 API 出发,往下找到它们落在哪里。

  1. spawn 全路径:tokio::spawn 到任务进队列的每一跳。大 future 先装箱;在 worker 线程上 spawn 进 LIFO 槽,在别的线程上 spawn 进注入队列。
  2. select! 与 join!:两个宏展开后都是一个 poll_fn。select! 每次 poll 随机选起点,一个分支完成就 drop 其余分支,cancel safety 问题由此而来。
  3. JoinSet、LocalSet、task_local:JoinSet 用两条链表记录哪些任务完成了;LocalSet 是一个自带队列的小调度器,跑在宿主任务里面;task_local! 在每次 poll 前后把值换进换出线程本地变量。
flowchart TB
  spawn["tokio::spawn"] --> bind["OwnedTasks::bind"]
  bind --> sched{在本运行时的 worker 上?}
  sched -->|是| lifo[LIFO 槽 / 本地队列]
  sched -->|否| inject[注入队列]
  sel["select! / join!"] --> pf[一个 poll_fn]
  pf --> branches[在当前任务里轮流 poll 各分支]
  js[JoinSet] --> spawn
  ls[LocalSet] --> own[自己的本地队列]

这一部分用到的内部结构都在前面讲过:任务的分配和 OwnedTasks 见「03 任务」,LIFO 槽、注入队列和预算见「04 调度器」。

💬 关联讨论

发起讨论
加载中...