Taskflow: C++复杂任务依赖图的并发任务调度库
·
文章目录
Taskflow 是一个现代 C++ 并发任务调度库,专注于表达复杂的任务依赖图(task dependency graphs),并利用高效的工作窃取(work-stealing)调度器在多核 CPU 上实现并行执行。它由 National Tsing Hua University 的研究人员开发,设计目标是兼顾表达力、性能和易用性,尤其适合用于构建 DAG(有向无环图)驱动的并行应用,如机器学习流水线、物理仿真、构建系统、自动化测试等。
GitHub 主页:https://github.com/taskflow/taskflow
文档:https://taskflow.github.io/
一、核心特性
- Header-only:无外部依赖,仅需包含头文件即可使用。
- 支持静态与动态任务图:
- 静态图:编译时或初始化时确定结构。
- 动态图:运行时可动态构建子图(如递归、条件分支)。
- 高效 work-stealing 调度器:基于 per-thread deque,减少锁竞争。
- GPU 任务支持(需 CUDA):可调度 CUDA kernel 或流。
- 条件任务(Condition Task):支持运行时分支(类似 if/else)。
- 模块化子图(Subflow):可嵌套任务图,实现递归或模块化设计。
- 性能优于 TBB flow_graph 和 OpenMP task(官方 benchmark 显示)。
二、基础使用示例
#include <taskflow/taskflow.hpp>
int main() {
tf::Executor executor;
tf::Taskflow taskflow;
auto [A, B, C, D] = taskflow.emplace(
[](){ std::cout << "Task A\n"; },
[](){ std::cout << "Task B\n"; },
[](){ std::cout << "Task C\n"; },
[](){ std::cout << "Task D\n"; }
);
A.precede(B, C); // A → B, A → C
B.precede(D); // B → D
C.precede(D); // C → D
executor.run(taskflow).wait();
return 0;
}
输出顺序保证:A 先执行,B/C 并行执行,D 最后执行。
三、高级用法详解
1. 动态子图(Subflow)
适用于递归、分治、运行时展开的任务结构。
tf::Task parent = taskflow.emplace([&](tf::Subflow& sf) {
for(int i = 0; i < 4; ++i) {
sf.emplace([i](){ std::cout << "Dynamic task " << i << "\n"; });
}
}).name("parent");
Subflow 内部任务会自动并行调度,parent 任务在所有子任务完成后才结束。
✅ 应用场景:并行遍历树、分治 FFT、动态任务生成(如游戏 AI 行为树)。
2. 条件任务(Condition Task)
运行时根据返回值决定下一个执行分支(类似 switch)。
auto cond = taskflow.emplace([]() -> int {
return rand() % 3; // 返回 0, 1, 或 2
}).name("cond");
auto t0 = taskflow.emplace([](){ std::cout << "Branch 0\n"; });
auto t1 = taskflow.emplace([](){ std::cout << "Branch 1\n"; });
auto t2 = taskflow.emplace([](){ std::cout << "Branch 2\n"; });
cond.precede(t0, t1, t2);
cond.branch(t0, t1, t2); // 返回 0→t0, 1→t1, 2→t2
✅ 应用场景:状态机、运行时策略选择、错误恢复路径。
3. GPU 任务(CUDA)
需启用 CUDA 支持(编译时定义 TF_CUDA)。
__global__ void add(int* x, int* y, int* z) {
*z = *x + *y;
}
tf::Task gpu_task = taskflow.emplace([&] (tf::cudaFlow& cf) {
int *x, *y, *z;
cf.memalloc(x, 1);
cf.memalloc(y, 1);
cf.memalloc(z, 1);
cf.memset(x, 2, sizeof(int));
cf.memset(y, 3, sizeof(int));
cf.kernel(dim3(1), dim3(1), 0, add, x, y, z);
// 可加 cf.copy(host_z, z, sizeof(int)) 回传
});
✅ 应用场景:异构计算流水线,CPU-GPU 协同任务图。
4. 任务复用与模块化(Composable Graphs)
通过 composed_of 复用子图:
tf::Taskflow module;
auto m1 = module.emplace([](){ std::cout << "M1\n"; });
auto m2 = module.emplace([](){ std::cout << "M2\n"; });
m1.precede(m2);
tf::Taskflow main;
auto t = main.composed_of(module).name("instance1");
auto u = main.composed_of(module).name("instance2");
t.precede(u);
executor.run(main).wait();
✅ 适用于构建可复用的算法模块(如预处理-求解-后处理流水线)。
5. 性能调优技巧
- 避免任务粒度过细:每个任务应有足够计算量(> 微秒级),否则调度开销占主导。
- 使用
tf::Executor(num_threads)指定线程数:默认为std::thread::hardware_concurrency()。 - 复用
Executor:创建一次,多次运行不同Taskflow,避免反复构建线程池。 - 监控任务图:使用
taskflow.dump(std::cout)输出 Graphviz 格式进行可视化。
四、与 TBB、OpenMP 对比
| 特性 | Taskflow | TBB flow_graph | OpenMP task |
|---|---|---|---|
| 表达力 | ⭐⭐⭐⭐⭐(DAG + 动态 + 条件) | ⭐⭐⭐(静态图为主) | ⭐⭐(简单依赖) |
| 性能 | 极高(lock-free work-stealing) | 高 | 中(依赖 runtime) |
| GPU 支持 | ✅(原生 CUDA) | ❌ | ❌(OpenMP 5.0+ 有,但生态弱) |
| 学习曲线 | 中 | 高 | 低 |
| 项目活跃度 | 高(持续更新) | 中(Intel 维护) | 高(标准) |
✅ 若你需要复杂控制流 + 高性能 + 现代 C++,Taskflow 是目前最推荐的选择。
五、典型应用场景
- 多阶段仿真流水线:网格生成 → 求解器 → 后处理 → 可视化,各阶段可并行或串行。
- 参数扫描与优化:每个参数组合是一个子图,并行执行。
- 构建系统替代:比 Make/Ninja 更灵活地表达依赖。
- AI 推理流水线:预处理 → 模型推理 → 后处理,支持 CPU/GPU 混合。
更多推荐



所有评论(0)