OpenMP任务调度
OpenMP中,任务调度主要用于并行的for循环当中,当循环中每次迭代的计算量不相等时,如果简单地给各个线程分配相同次数的迭代的话,会造成各个线程计算负载不均衡,这会使得有些线程先执行完毕,有的后执行完,造成某些cpu核空闲,影响程序性能。
举例:
int i,j;
int a[100][100]={0};
for(i=0;i<100;i++)
{
for(j=i;j<100;j++)
{
a[i][j]=i*j;
}
}
如果最外层循环并行化的话,比如使用4个线程,如果给每个线程平均分配25次循环迭代计算的话,显然i=0和i=99的计算量相差了100倍,那么各个线程间可能出现较大的负载不平衡情况。为了解决这些问题,openMP以供了几种对for循环并行化的任务调度方案。使用schedule子句来实现。
1.schedule子句用法
使用格式:
schedule(type[,size])
schedule有两个参数,type和size,size参数是可选的。
(1)type参数
表示调度的类型,有四种调度类型如下:
dynamic
guided
runtime
static
实际上只有static、dynamic、guided三种调度方式,runtime实际上是根据环境变量来选择前三种中的某种类型。
(2)size参数
size参数表示循环迭代此时,size参数必须是整数。static、dynamic、guided三只调度方式都可以使用size参数,也可以不使用size参数。当type类型是runtime时,size不需要使用。
2.静态调度(static)
当parallel for编译知道语句没有带schedule子句时,大部分系统中默认采用static调度方式,这种调度方式非常简单。假设有n次循环迭代,t个线程,那么给每个线程静态分配大概大约n/t次迭代计算。大约的说法是因为n/t不一定是整数,因此实际分配的迭代次数可能存在差1的情况,如果指定size参数,那么可能相差一个size。
静态调度时可以不使用size参数,也可以使用size参数。
不使用size参数时,**分配给每个线程的是n/t次连续的迭代,**用法如下:
schedule(static)
代码:
#pragma omp parallel for schedule(static)
for(i=0;i<10;i++)
{
cout<<"i="<<i<<", thread="<<omp_get_thread_num()<<endl;
}
执行结果输出
可以看到,迭代0、1分配给了线程0,迭代2、3分配给了线程1。之后迭代4给了2,5给了3,6给4,7给5,8给了6,9给7。
使用size参数:
schedule(static,2)
#pragma omp parallel for schedule(static,2)
for(i=0;i<10;i++)
{
cout<<"i="<<i<<", thread="<<omp_get_thread_num()<<endl;
}
输出为:
可以看到,每个线程一次分配了2次(size大小)连续的迭代计算。
3.动态调度(dynamic)
动态调度是动态的将迭代分配到各个线程,动态调度可以使用size参数也可以不使用size参数,不使用size参数时是将迭代逐个分配到各个线程;使用size参数时,每次分配给线程的迭代次数为指定的size次。
不带size参数时:
#pragma omp parallel for schedule(dynamic)
for(i=0;i<10;i++)
{
cout<<"i="<<i<<", thread="<<omp_get_thread_num()<<endl;
}
带size参数:
#pragma omp parallel for schedule(dynamic,3)
for(i=0;i<10;i++)
{
cout<<"i="<<i<<", thread="<<omp_get_thread_num()<<endl;
}
4.guided调度(guided)
guided调度是一种采用指导性的启发式自调度方法。开始时每个线程都会分到较大的迭代块,之后分配到的迭代块回逐渐递减,迭代块的大小会按照指数级下降到指定的size大小,如果没有指定size参数,则迭代块大小最小会降到1.
举例:
#pragma omp parallel for schedule(guided,2),num_threads(3)
for (i = 0; i < 10; i++)
{
cout << "i=" << i << ", thread=" << omp_get_thread_num() << endl;
}
输出为:
迭代次数0,1,2,3,9,10分配给线程0。4,5,6分配给线程1,剩下7,8分配给线程2。分配的迭代次数呈现递减趋势,最后递减至2次。
5.runtime调度
runtime调度不是和前面三种调度方式似的真实调度方式。而是在运行时更加环境变量OMP_SCHEDULE来确定调度类型,最终使用的调度类型依然是上述三只调度种的某种。例如unix系统中,可以使用setenv命令来设置OMP_SCHEDULE环境变量:setenv OMP_SCHEDULE "dynamic,2"
该命令设置调度类型为动态,size为2。而windows环境中,可以在”系统属性->高级->环境变量“对话框中设置环境变量。
以上文字内容和代码主要转载自:
https://blog.csdn.net/drzhouweiming/article/details/1175848
在此表示感谢!