原文: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子句详解 (转载)的更多相关文章

  1. OpenMP并行程序设计——for循环并行化详解

    在C/C++中使用OpenMP优化代码方便又简单,代码中需要并行处理的往往是一些比较耗时的for循环,所以重点介绍一下OpenMP中for循环的应用.个人感觉只要掌握了文中讲的这些就足够了,如果想要学 ...

  2. 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)

    如约而至,Java 10 正式发布!   3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...

  3. Java 反射 设计模式 动态代理机制详解 [ 转载 ]

    Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...

  4. Linux下的I/O复用与epoll详解(转载)

    Linux下的I/O复用与epoll详解 转载自:https://www.cnblogs.com/lojunren/p/3856290.html  前言 I/O多路复用有很多种实现.在linux上,2 ...

  5. malloc 与 free函数详解<转载>

    malloc和free函数详解   本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...

  6. jQuery的deferred对象详解(转载)

    本文转载自: jQuery的deferred对象详解(转载)

  7. GridView内容详解(转载)

    GridView内容详解(转载) GridView是ASP.NET界面开发中的一个重要的控件,对GridView使用的熟练程度直接影响软件开发的进度及功能的实现.(车延禄)GridView的主要新特性 ...

  8. Oracle外部表详解(转载)

    (外部表创建主要注意创建目录访问权限问题.目录路径格式无空格等不相关字符,即必须是当前表访问用户可以访问:关于表中行数的限制问题,如果不加限制注意添加reject limit unlimited:表中 ...

  9. C#中的 特性 详解(转载)

    本篇幅转载于:http://www.cnblogs.com/rohelm/archive/2012/04/19/2456088.html C#中特性详解 特性提供了功能强大的方法,用于将元数据或声明信 ...

随机推荐

  1. Modern Operating Systems(Ⅰ)——2014.12.15

    进程   进程模型     进程就是一个正在执行的程序的实例  值得注意的是,若一个程序运行了两遍,则算作两个进程 创建进程 在通用系统中,有四种主要事件导致进程的创建 ①系统的初始化 ②执行了 正在 ...

  2. jQuery实现鼠标拖动改变Div高度

    最近项目中需要在DashBoard页面做一个事件通知栏,该通知栏固定位于页面底部,鼠标拖动该DIV实现自动改变高度扩展内容显示区域. 以下是一个设计原型,基于jQuery实现,只实现了拖动效果,没有做 ...

  3. visual c++ 2010安装失败导致CRM2015安装失败

    记录一下: 今天重新安装CRM2015时碰到以下错误: 安装一个或多个缺少的必备组件失败...,查看日志发现是 Microsoft Visual C++ 运行时 的安装失败,但查看系统发现vc++20 ...

  4. win8 系统无法正常安装.net framework 2.0和3.0框架如何解决

    在安装.net framework2.0框架的时候一直提示要用户从网上面下载框架,你点击下载好的安装包也是无法安装的.这个时候就需要你使用离线的安装包来进行问题的解答附件在此http://pan.ba ...

  5. linux下服务端实现公网数据转发

    之前在腾讯上使用了一个免费的公网服务器,只有7天,linux系统. 其实有这样的想法,是因为有个研二的师弟问我怎么样才能让连个局域网的电脑通信. 我跟他说了两种方法,一种是找个公网服务器来转发数据,另 ...

  6. JavaIO之File类

    Java-IO之File类 Java-IO之File类 1. File类 1.1. File类说明 1.2. 体验 File 类 1.3. 构造一个 File 类实例: 1.4. 路径: 1.4.1. ...

  7. RTTI 运行时类型识别 及异常处理

    RTTI   运行时类型识别 typeid  ------  dynamic_cast dynamic_cast 注意事项: 1.只能应用于指针和引用之间的转化 2.要转换的类型中必须包含虚函数 3. ...

  8. 把cmd信息中的正常和异常输出分别输出到不同txt文件中

    场景一: 1.大量滚动信息容纳不下,在小黑屏中被冲刷掉. 2.希望把正常输出和异常输出分别输出到不同地方. 相关命令 一共有4个输出到文件的命令,现以jar命令打war包举例说明: 命令 说明 举例  ...

  9. Java对象的序列化和反序列化

    对象的序列化是指将对象转换为字节序列的过程 对象的反序列化是指将字节序列恢复对象的过程 主要有两种用途: 1.把对象的字节序列永久地保存在硬盘上,通常放在一个文件中. 2.在网络上传输对象的字节序列. ...

  10. maxiang.io css

    /**设置你自己的CSS.例如:h1 { border-bottom: 1px solid #ccc; line-height:1.6;}body { background:#FDFFD0} **/p ...