zoukankan      html  css  js  c++  java
  • OpenMP编程的任务调度控制

    在OpenMP的for任务分担中,各个线程的任务划分是可以由程序员控制调整的。考虑这样一种情况,当在一个循环中每次迭代的计算量不相等时,如果根据系统默认简单的给每个线程分配相同次数的迭代量的话,会导致有些线程先执行玩,有些线程后执行完,造成CPU核的空闲,降低程序的运行效率。这种情况下就有必要人为的对各个线程的任务划分进行分配。


    例如对如下的循环:

    #pragma omp parallel for 
    	for (int i = 0; i < 100; i++)
    	{
    		cout << i*i << endl;
    	}

    显然最后几次的计算量是远远大于前几次的计算量的,解决这种由于各个线程间均分迭代次数造成的负载不平衡的问题,可以通过schedule子句的使用来避免。


    schedule子句的用法


    使用格式:

    schedule(type,size)

    type表示调度类型,共有4种类型可选:

    • static
    • dynamic
    • guided
    • runtime

    size参数定义了迭代次数最小的划分单位,每个线程依次分配size个迭代次数。


    static静态调度


    #include<iostream>
    #include"omp.h"
    
    using namespace std;
    
    void main()
    {
    #pragma omp parallel for schedule(static,3)
    	for (int i = 0; i < 9; i++)
    	{
    		printf("i=%d, thread_id=%d
    ", i, omp_get_thread_num());
    	}
    	system("pause");
    }

    输出:



    从打印结果可以看出每个线程依次分配到3个连续的迭代计算。


    dynamic动态调度


    动态调度是动态的将迭代分配到各个线程上,可以使用size参数也可以不使用size参数,不适用size参数情况下size值默认为1,根据每个线程的完成情况每次再分配2个迭代给已完成迭代任务的线程,使用size参数则每次分配size个迭代次数。较快迭代完成的线程可能执行更多次迭代,较慢的线程执行较少的迭代,以此来解决各线程间负载分配不均衡的问题。


    示例:

    #include<iostream>
    #include"omp.h"
    
    using namespace std;
    
    void main()
    {
    #pragma omp parallel for schedule(dynamic,2)
    	for (int i = 0; i < 12; i++)
    	{
    		printf("i=%d, thread_id=%d
    ", i*i*i*i, omp_get_thread_num());
    	}
    	system("pause");
    }

    输出:



    执行乘法运算,i比较小的时候计算量小,所以可以看到编号为0的线程执行了6次,编号为1、2和3的线程分别执行了2次。


    guided调度


    guided调度跟dynamic动态调度类似,是一种采用指导性的启发式自调度方法。刚开始时候每个线程会分配到较大的迭代块,之后每次分配到的迭代块会以指数级下降,直到下降到自定义的size大小,如果没有定义size,则默认为1。


    runtime调度


    runtime调度根据运行时的环境变量OMP_SCHEDULE来确定调度类型,最后还是会落实到schedule、dynamic和guided中的一种上来。

    例如在unix系统中,可以使用setenv命令来设置OMP_SCHEDULE环境变量:

      setenv OMP_SCHEDULE “dynamic, 2”  

     如果程序中选择runtime调度,那么上述命令设置调度类型为动态调度,动态调度的size为2。在windows环境中,可以在“系统属性|高级|环境变量”对话框中进行设置环境变量。


    sections制导指令


    for制导指令用于迭代计算的任务分配,sections制导指令用于非迭代计算的任务分配,sections的语法格式如下:

    #pragma omp parallel sections[子句]


    #include<iostream>
    #include"omp.h"
    
    using namespace std;
    
    void main()
    {
    #pragma omp parallel sections
    	{
    #pragma omp section
    		{
    			for (int i = 0; i < 4; i++)
    			{
    				printf("i=%d, thread_id=%d
    ", i, omp_get_thread_num());
    			}
    		}
    #pragma omp section
    		{
    
    			for (int i = 0; i < 4; i++)
    			{
    				printf("j=%d, thread_id=%d
    ", i, omp_get_thread_num());
    			}
    		}
    	}
    	system("pause");
    }

    输出:



    sections语句块中一共有2个section段落,所以生成了2个线程并行执行。


    single制导指令


    在parallel制导指令产生的并行域中的语句,一般会默认生成4个不同的线程对相同的语句分别执行一次,如果想要其中某些操作只执行一次,可以使用single制导指令,其后的语句块只会被单个线程执行。

    #include<iostream>
    #include"omp.h"
    
    using namespace std;
    
    void main()
    {
    #pragma omp parallel
    	{
    #pragma omp single
    		{
    			printf("single thread_id=%d
    ", omp_get_thread_num());
    		}
    
    		printf("多线程执行,thread_id=%d
    ", omp_get_thread_num());
    	}
    	system("pause");
    }

    输出:



    由single引导的语句块只执行了一次,第二个printf语句没有single指令,所以被4个不同的线程分别执行了一次。


  • 相关阅读:
    spring-102-spring全注解快速实现事务
    spring-101-springAOP
    spring-201-springmvc基于MappingJacksonValue 实现JSONP
    啥是JSONP---转
    request.getSession(boolean create)的正确使用姿势
    spring-003-Resource资源
    spring-002-Ioc bean配置
    spring-001-Ioc 顶层容器
    为企业提供免费代码安全扫描服务(每月限一次)
    圆满完成平安科技Web安全与App应用安全测试培训!
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9411891.html
Copyright © 2011-2022 走看看