并行计算的开销
你的成本模型是错误的。
理想的并行计算时间为:
Tpar(ideal) = N * t / C + Pstart + Pend
Pstart
表示启动并行处理所需的时间,Pend
表示完成并行处理所需的时间。通常情况下,Pstart
需要数十毫秒的时间。
不知道您是否熟悉OpenMP(虽然了解它是一件好事),但对于我们来说,它是一种将工作分配给团队线程的线程模型。以下图表显示了某些命令与线程团队大小相关的开销:
结论是启动并行处理(parallel for
)可能很昂贵,并且随着线程数量增加而增加。结束并行处理(barrier
)也有类似的成本。
实际上,如果您查看TBB的教程,第3.2.2节(“自动块划分”)中写道:
注意:通常,循环至少需要花费100万个时钟周期才能使parallel_for提高其性能。例如,在2 GHz处理器上至少需要500微秒的循环可以从parallel_for中受益。
实现更快的速度
加速此类代码的最佳方法是仅在存在大量操作和/或调整执行工作的线程数量,以便每个线程都有足够的工作量时才并行执行操作。在TBB中,可以通过以下方式实现类似的行为:
#include <tbb/parallel_for.h>
// . . .
if(work_size>1000)
tbb::serial::parallel_for( . . . )
else
tbb::parallel_for( . . . )
// . . .
您需要调整的是1000
这个数字,使其足够高,以便从并行性中获得收益。
您还可以减少线程数,因为这会在一定程度上减少开销:
tbb::task_scheduler_init init(nthread);
TBB 还可以执行动态负载平衡(详见
这里)。如果你期望循环迭代/任务的运行时间分布广泛,那么这会很好,但如果预期运行时间相同,则会造成不必要的开销。我不确定 TBB 是否具有静态调度功能,但值得研究一下。
如果人们在没有强烈承诺使用 TBB 的情况下到达这里,在 OpenMP 中,您可以这样做:
#pragma omp parallel for if(work_size>1000) num_threads(4) schedule(static)