任务与定序¶
一个任务开始之前什么必须先完成 —— 运行时如何自己推出这件事,以及在它推不出来时你该用哪些接口自己说。
本章是什么¶
作用域与放置 回答代码在哪里跑。本章回答什么时候跑 —— 运行时真正执行的那张依赖图是什么形状。
多数程序永远用不上它。运行时会从每个任务触碰的缓冲区、以及每个参数声明的方向推导出这张图,默认情况下这个推导就是对的。你来到这一章,是因为它不够用了:
- 运行时推出了一条并不是真实依赖的边,把本可以重叠的工作串行化了;
- 它推不出一条真实存在的边,因为那个关系并不体现为缓冲区重叠;
- 或者这份工作本身是有条件的,你希望任务被跳过而不是被派发。
目录¶
| 页面 | 覆盖内容 |
|---|---|
| 依赖模型 | 任务是什么、边是怎么推出来的、为什么语句顺序什么都不表达 |
| 运行时作用域 | pl.scope / pl.manual_scope / ScopeMode —— 自动跟踪的边界 |
| 声明一条边 | TaskId 与 deps= —— 经 pl.at 块或 pl.submit,以及用 TaskId 数组做扇入 |
| 精修依赖图 | pl.no_dep、predicate=、allow_early_resolve=、pl.system.task_dummy |
阅读顺序¶
先读 依赖模型 —— 其余各页里的每个接口,要么是把这套推导关掉的开关,要么是在它之上做加法:
开始之前值得先知道一件事:显式边与自动跟踪不是二选一。 deps= 在普通的 auto 作用域里就能用,最终等待集合是两者的并集。动用 pl.manual_scope 是另一个、也更重的决定 —— 它把推导整个关掉,此后每条边都归你声明。
参见¶
- 作用域与放置 —— 姊妹问题:代码由哪块硬件执行。
- 类型 § 参数方向 —— 运行时据以推边的那个声明。
- 算子 —— 本章提到的算子的一行式条目。
- AutoDeriveTaskDependencies —— 发出编译器侧那些边的 pass。