博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OpenMP 中的线程任务调度
阅读量:7108 次
发布时间:2019-06-28

本文共 2179 字,大约阅读时间需要 7 分钟。

OpenMP中任务调度主要针对并行的for循环,当循环中每次迭代的计算量不相等时,如果简单地给各个线程分配相同次数的迭代,则可能会造成各个线程计算负载的不平衡,影响程序的整体性能。

如下面的代码中,如果每个线程执行的任务数量平均分配,有的线程会结束早,有的线程结束晚:

1 #include
2 #include
3 4 int main(){ 5 int a[100][100] = {
0}; 6 #pragma omp parallel for 7 for (int i =0; i < 100; i++){ 8 for(int j = i; j < 100; j++ ) 9 a[i][j] = ((i%7)*(j%13)%23);10 }11 return 0;12 }

 

为此,OpenMP提供了schedule子句来实现任务的调度。

schedule子句:

  schedule(type[, size]),

  参数type是指调度的类型,可以取值为static,dynamic,guided,runtime四种值。其中runtime允许在运行时确定调度类型,因此实际调度策略只有前面三种。

  参数size表示每次调度的迭代数量,必须是整数。该参数是可选的。当type的值是runtime时,不能够使用该参数。

1.静态调度static

  大部分编译器在没有使用schedule子句的时候,默认是static调度。static在编译的时候就已经确定了,那些循环由哪些线程执行。

  当不使用size 时,将给每个线程分配┌N/t┐个迭代。当使用size时,将每次给线程分配size次迭代。

  如下面代码:

1 #include
2 #include
3 int main(){ 4 int a[100][100] = {
0}; 5 #pragma omp parallel for schedule(static) 6 //#pragma omp parallel for schedule(static,5) 7 for (int i =0; i < 100; i++){ 8 printf("id=%d i=%d\n",omp_get_thread_num(),i); 9 }10 return 0;11 }
View Code

  在四核机器上执行:

  (1)当不使用参数时,100/4=25,0-24由1号线程执行;25-49由2号线程执行;50-74由3号线程执行;75-99由4号线程执行

  (1)当不使用参数时,x(x=0,1,2,3)线程执行((n/5)%4)任务。其中n=0-99。

2.动态调度dynamic

  动态调度依赖于运行时的状态动态确定线程所执行的迭代,也就是线程执行完已经分配的任务后,会去领取还有的任务。由于线程启动和执行完的时间不确定,所以迭代被分配到哪个线程是无法事先知道的。

  当不使用size 时,是将迭代逐个地分配到各个线程。当使用size 时,逐个分配size个迭代给各个线程。

  如下面代码:

1 #include
2 #include
3 int main(){ 4 int a[100][100] = {
0}; 5 #pragma omp parallel for schedule(dynamic) 6 //#pragma omp parallel for schedule(dynamic,5) 7 for (int i =0; i < 100; i++){ 8 printf("id=%d i=%d\n",omp_get_thread_num(),i); 9 }10 return 0;11 }
View Code

3.启发式调度guided

   采用启发式调度方法进行调度,每次分配给线程迭代次数不同,开始比较大,以后逐渐减小。

  size表示每次分配的迭代次数的最小值,由于每次分配的迭代次数会逐渐减少,少到size时,将不再减少。如果不知道size的大小,那么默认size为1,即一直减少到1。具体采用哪一种启发式算法,需要参考具体的编译器和相关手册的信息。

 

三种运行方式总结:

静态调度static:每次哪些循环由那个线程执行时固定的,编译调试。由于每个线程的任务是固定的,但是可能有的循环任务执行快,有的慢,不能达到最优。

动态调度dynamic:根据线程的执行快慢,已经完成任务的线程会自动请求新的任务或者任务块,每次领取的任务块是固定的。

启发式调度guided:每个任务分配的任务是先大后小,指数下降。当有大量任务需要循环时,刚开始为线程分配大量任务,最后任务不多时,给每个线程少量任务,可以达到线程任务均衡。

转载地址:http://mvphl.baihongyu.com/

你可能感兴趣的文章
Jenkins-Publish HTML reports
查看>>
KVO 键值观察
查看>>
iOS开发网络篇—发送GET和POST请求(使用NSURLSession)
查看>>
Adaptability Is Accessibility
查看>>
HDU_1227_Fast Food_动态规划
查看>>
实验验证redis的快照和AOF
查看>>
临时表的应用
查看>>
码农的福利来了, 编程在线Androd 客户端上线了
查看>>
sys.stdout.write与sys.sterr.write(二)
查看>>
多继承时,多个基类中存在型别相同的虚函数,该怎么做?
查看>>
shell配置,选择,环境变量修改(ORACLE_HOME,ORACLE_SID),无法使用sqlplus
查看>>
Design Hint for Inheritance(继承设计的一些小贴士)
查看>>
java 时间格式化函数
查看>>
python参数
查看>>
P1614 爱与愁的心痛
查看>>
Windows上使用Objective-c和Cocoa
查看>>
android ui事件处理分析
查看>>
我的爹娘(二)
查看>>
ctrl+c关闭多线程python程序
查看>>
Algorithm4.子数组求和贪心
查看>>