OpenMP并行构造的schedule子句详解 (转载)
原文:http://blog.csdn.net/gengshenghong/article/details/7000979
schedule的语法为:
schedule(kind, [chunk_size])
kind:
• static: Iterations are divided into chunks of size chunk_size. Chunks are assigned to threads in the team in round-robin fashion in order of thread number.
• dynamic: Each thread executes a chunk of iterations then requests another chunk until no chunks remain to be distributed.
• guided: Each thread executes a chunk of iterations then requests another chunk until no chunks remain to be assigned. The chunk sizes start large and shrink to the indicated chunk_size as chunks are scheduled.
• auto: The decision regarding scheduling is delegated to the compiler and/or runtime system.
• runtime: The schedule and chunk size are taken from the run-sched-var ICV
(1)schedule的作用:
上面知道,schedule只能用于循环并行构造中,其作用是用于控制循环并行结构的任务调度。一个简单的理解,一个for循环假设有10此迭代,使用4个线程去执行,那么哪些线程去执行哪些迭代呢?可以通过schedule去控制迭代的调度和分配,从而适应不同的使用情况,提高性能。
(1)schedule语法:
schedule(kind [, chunk_size]),其中kind可以取值为static,dynamic,guided,auto,runtime。其中,测试发现,auto貌似是不行的(可能是Fortran才支持?不清楚)。参数chunk_size是一个size的参数,所以是整数了。这里的runtime在后面分析,其实本质上是前面三种类型之一。
所以,schedule的类型一共是三种:static、dynamic、guided。下面先逐一分析这三种,最后再来了解runtime的含义。
(2)静态调度static:
大部分的编译器实现,在没有使用schedule子句的时候,系统就是采用static方式调度的。
对于schedule(static,size)的含义,OpenMP会给每个线程分配size次迭代计算。这个分配是静态的,“静态”体现在这个分配过程跟实际的运行是无关的,可以从逻辑上推断出哪几次迭代会在哪几个线程上运行。具体而言,对于一个N次迭代,使用M个线程,那么,[0,size-1]的size次的迭代是在第一个线程上运行,[size, size + size -1]是在第二个线程上运行,依次类推。那么,如果M太大,size也很大,就可能出现很多个迭代在一个线程上运行,而某些线程不执行任何迭代。需要说明的是,这个分配过程就是这样确定的,不会因为运行的情况改变,比如,我们知道,进入OpenMP后,假设有M个线程,这M个线程开始执行的时间不一定是一样的,这是由OpenMP去调度的,并不会因为某一个线程先被启动,而去改变for的迭代的分配,这就是静态的含义。分析下面的例子:
#include <omp.h>
#define COUNT 4*3 int main(int argc, _TCHAR* argv[])
{
#pragma omp parallel for schedule(static,4)
for(int i = ;i < COUNT; i++)
{
printf("Thread: %d, Iteration: %d\n", omp_get_thread_num(), i);
} return ;
}
下面是其中多次运行的几次结果(四核系统,所以线程数量为4):

从左到由假设为结果1/2/3,从结果可以看到,无论是哪一个线程先启动,team内的ID为0的线程,总是会执行0,1,2,3对应的迭代,team内ID为1的线程,总是会执行4,5,6,7对应的迭代,team内ID为2的线程,总是会执行8,9,10,11的线程,而team内线程ID为4的线程,并没有去执行任何迭代。如果把上面的size的大小改为12,那么无论如何,所有的迭代都只会在线程0上执行,其实就跟串行的效果一样了。对于这里的情况,4个线程,却只使用了3个线程去计算,所以这样分配当然是不平衡的。
上面是针对给定size的情况,如果不指定size,只是指定static类型,那么OpenMP为使用迭代数/线程数作为size的值,采取同样的策略来进行分配,这样每个线程执行的迭代数目就是一样的(注意,如果迭代数/线程数不是整除的,那就不完全一样了,但是整体是比较平衡的),一般而言,这就是不加任何schedule修饰下的调度情况了。
(3)动态调度dynamic
动态调度迭代的分配是依赖于运行状态进行动态确定的,所以哪个线程上将会运行哪些迭代是无法像静态一样事先预料的。对于dynamic,没有size参数的情况下,每个线程按先执行完先分配的方式执行1次循环,比如,刚开始,线程1先启动,那么会为线程1分配一次循环开始去执行(i=0的迭代),然后,可能线程2启动了,那么为线程2分配一次循环去执行(i=1的迭代),假设这时候线程0和线程3没有启动,而线程1的迭代已经执行完,可能会继续为线程1分配一次迭代,如果线程0或3先启动了,可能会为之分配一次迭代,直到把所有的迭代分配完。所以,动态分配的结果是无法事先知道的,因为我们无法知道哪一个线程会先启动,哪一个线程执行某一个迭代需要多久等等,这些都是取决于系统的资源、线程的调度等等。看下面的例子:
#include <omp.h>
#include <Windows.h>
#define COUNT 4*3 int main(int argc, _TCHAR* argv[])
{
#pragma omp parallel for schedule(dynamic)
for(int i = ;i < COUNT; i++)
{
printf("Thread: %d, Iteration: %d\n", omp_get_thread_num(), i);
} return ;
}
下面也是多次运行的结果:

事实上,这个结果容易给人误解,以结果2来分析,为什么线程1先执行完,其对应的迭代却是1而不是0呢?而且接下来也是3而不是2呢?不是先执行完的先分配么?我的理解是,这里,刚开始的时候,我们不知道线程的状态,实际的一种可能是,线程0先启动了,所以会去执行迭代0里面的内容,但是,只是开始去执行,而这里用printf测试,是输出的结果,输出的顺序不代表开始执行此迭代的顺序,所以可能的情况是,线程0执行迭代0还没有完成的时候,线程1空闲,为线程1分配了迭代1,然后线程1一直运行迭代1的时候,线程0仍然在运行迭代0,这中间,线程2可能会分配了迭代2开始执行,线程1又获得了分配机会,被分配了迭代3等等。。。总之,这里的输出顺序是不代表每一个迭代开始被分配执行的时间顺序的。总之,理解这个动态的过程,简单理解,就是“谁有空,给谁分配一次迭代让它去跑!" :)
那么同样,dynamic也可以有一个size参数,size表示,每次线程执行完(空闲)的时候给其一次分配的迭代的数量,如果没有知道size(上面的分析),那么每次就分配一个迭代。有了前面的理解,这个size的含义是很容易理解的了。
(4)guided调度
类似于动态调度,但每次分配的循环次数不同,开始比较大,以后逐渐减小。size表示每次分配的迭代次数的最小值,由于每次分配的迭代次数会逐渐减少,较少到size时,将不再减少。如果不知道size的大小,那么默认size为1,即一直减少到1。具体是如何减少的,以及开始比较大(具体是多少?),参考相关手册的信息。
(5)runtime
runtime表示根据环境变量确定上述调度策略中的某一种,默认也是静态的(static)。
控制schedule环境变量的是OMP_SCHEDULE环境变量,其值和上面的三中类型一样了,比如:
setenv OMP_SCHEDULE “dynamic, 5”
就是schedule(dynamic,5)的含义了。
OpenMP并行构造的schedule子句详解 (转载)的更多相关文章
- OpenMP并行程序设计——for循环并行化详解
在C/C++中使用OpenMP优化代码方便又简单,代码中需要并行处理的往往是一些比较耗时的for循环,所以重点介绍一下OpenMP中for循环的应用.个人感觉只要掌握了文中讲的这些就足够了,如果想要学 ...
- 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)
如约而至,Java 10 正式发布! 3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
- Linux下的I/O复用与epoll详解(转载)
Linux下的I/O复用与epoll详解 转载自:https://www.cnblogs.com/lojunren/p/3856290.html 前言 I/O多路复用有很多种实现.在linux上,2 ...
- malloc 与 free函数详解<转载>
malloc和free函数详解 本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...
- jQuery的deferred对象详解(转载)
本文转载自: jQuery的deferred对象详解(转载)
- GridView内容详解(转载)
GridView内容详解(转载) GridView是ASP.NET界面开发中的一个重要的控件,对GridView使用的熟练程度直接影响软件开发的进度及功能的实现.(车延禄)GridView的主要新特性 ...
- Oracle外部表详解(转载)
(外部表创建主要注意创建目录访问权限问题.目录路径格式无空格等不相关字符,即必须是当前表访问用户可以访问:关于表中行数的限制问题,如果不加限制注意添加reject limit unlimited:表中 ...
- C#中的 特性 详解(转载)
本篇幅转载于:http://www.cnblogs.com/rohelm/archive/2012/04/19/2456088.html C#中特性详解 特性提供了功能强大的方法,用于将元数据或声明信 ...
随机推荐
- IT界里的生日
MS-DOS 1981年7月27日 windows 3.0 1990年5月22日 windows 3.11 1992年3月18日 Windows 95 1995年8月24日 Windows ...
- 萌萌的websocket原理解析
转载自:http://www.zhihu.com/question/20215561 一.WebSocket是HTML5出的东西(协议),也就是说HTTP协议没有变化,或者说没关系,但HTTP是不支持 ...
- Cannot assign requested address出现的原因及解决方案
今天使用python多线程请求服务时,出现Cannot assign requested address错误 网上找了下原因,大致上是由于客户端频繁的连服务器,由于每次连接都在很短的时间内结束,导致很 ...
- assert的用法
assert用来调试时,判断一个语句是否为真. assert是宏,而不是函数.在C的assert.h 头文件中. assert的作用是先计算表达式 expression ,如果其值为假(即为0),那么 ...
- Linux_10------Linux之shell编程------变量
.-9 vim num.sh #! /bin/bash num1=$1 num2=$2 sum=$(($num1+$num2)) #变量sum是num1和num2的综合 echo $sum 执行 ./ ...
- Handlebars模板库浅析
Handlebars模板库简单介绍 Handlebars是JavaScript一个语义模板库,通过对view(模板)和data(ajax请求的数据,一般是json)的分离来快速构建Web模板.它采用& ...
- apk添加系统签名
上一节,可以通过添加su的方式获取系统权限,但这种存在安全隐患,故不推荐,本文通过获取数字签名方式获取系统权限. 在我们的AndroidManifest.xml中添加 android:share ...
- iOS 判断字符串是否为空
写一个字符串的扩展,实现判断字符串是否为空- (BOOL) isBlankString { if ([self isEqualToString:@"(null)"]) { retu ...
- 收藏网址 ios开源库
http://www.csdn.net/article/2015-07-21/2825264-27-ios-open-source-libraries/1
- gridview填充剩下的空间
设置不要在控间中滑动: public class DeliverGridView extends GridView { public DeliverGridView(Context context, ...