一、引言
通过前边的介绍,知道了并行区域,默认情况下会自动生成与CPU个数相等的线程,然后并行执行并行区域中的代码,对于并行区域中的for循环,有特殊的声明方式,这样不同的线程可以分别运行for循环变量的不同部分。通过锁同步(atomic、critical、mutex函数)或事件同步(nowait、signal、section、master)来实现并行区域的同步控制。
具体的调度策略均由底层完成,本节介绍几种可以在上层对for循环进行控制的调度策略。
二、调度策略
调度策略 功能 适用情况
static 循环变量区域分为n等份,每个线程评分n份任务 各个cpu的性能差别不大
dynamic 循环变量区域分为n等份,某个线程执行完1份之后执行其他需要执行的那一份任务 cpu之间运行能力差异较大
guided 循环变量区域由大到小分为不等的n份,运行方法类似于dynamic 由于任务份数比dynamic,所以可以减少调度开销
runtime 在运行时来适用上述三种调度策略中的一种,默认是使用static
三、示例
1. static
#include
输出:
2. dynamic
代码:
#include
输出:
本次执行ID为1的线程分到了的循环变量任务为0~1,4~5,8~9。
再次执行如下:
本次执行ID为1的线程分到了任务2~3,6~7
3. guided
guided调度策略与dynamic区别在于,所分的任务块是从大到小排列的。具体分块算法为:每块的任务大小为:[迭代次数/线程个数的二倍]。其中每个任务的最小迭代次数由guided声明决定,默认是1。
举例说明:
#pragma omp for schedule[guided, 80]
for (int i = 0; i < 800; ++i){}
有两个cpu,那么任务分配如下:
第一个任务:[800/2*2] = 200
第二个任务:第一个任务分了200,还有600,那么[600/2*2] = 150
第三个任务:第二个任务分了150,还有450,那么[450/2*2] = 113
第四个任务:第三个任务分了113,还有337,那么[337/2*2] = 85
第五个任务:第四个任务分了85,还有252,那么[252/2*2] = 63,小于声明的80,那么这里为80
第六个任务:第五个任务分了80,还有172,根据声明,这里为80(因为会小于80)
第七个任务:第六个任务分了80,还有92,根据声明,这里为80(因为会小于80)
第八个任务:第七个任务分了80,还有12,根据声明,这里为12(因为不够80)
我在VS2008中没有看到guide的效果。
4. runtime
运行时底层动态选择调度策略。
四、小结
介绍了四种线程调度策略:static、dynamic、guided、runtime。
通过一些列的的介绍,大家若将所有的示例代码都跑一遍,应该可以掌握OpenMP的一些知识。
THE END