【问题标题】:How does the omp ordered clause work?omp 有序子句如何工作?
【发布时间】:2012-10-24 19:39:58
【问题描述】:
vector<int> v;

#pragma omp parallel for ordered schedule(dynamic, anyChunkSizeGreaterThan1)
    for (int i = 0; i < n; ++i){
            ...
            ...
            ...
#pragma omp ordered
            v.push_back(i);
    }

这用n 大小的有序列表填充v

当到达omp ordered 块时,所有线程都需要等待可能的最低迭代线程完成,但是如果没有线程被指定为特定的迭代呢?还是 OpenMP 运行时库总是确保最低迭代由某个线程处理?

还有为什么建议ordered 子句与dynamic schedule 一起使用? static schedule 会影响性能吗?

【问题讨论】:

    标签: c++ parallel-processing openmp


    【解决方案1】:

    ordered 子句的工作方式如下:不同的线程并发执行,直到遇到ordered 区域,然后按照与串行循环中执行的顺序相同的顺序依次执行。这仍然允许一定程度的并发性,尤其是在 ordered 区域之外的代码部分具有大量运行时间的情况下。

    没有特别的理由使用dynamic 调度而不是具有小块大小的static 调度。这完全取决于代码的结构。由于ordered 引入了线程之间的依赖关系,如果与schedule(static) 使用默认块大小,则第二个线程必须等待第一个线程完成所有迭代,然后第三个线程必须等待第二个线程完成所有迭代完成它的迭代(因此也完成第一个迭代),依此类推。使用 3 个线程和 9 次迭代(每个线程 3 个)可以轻松地对其进行可视化:

    tid  List of     Timeline
         iterations
    0    0,1,2       ==o==o==o
    1    3,4,5       ==.......o==o==o
    2    6,7,8       ==..............o==o==o
    

    = 表明线程正在并行执行代码。 o 是线程正在执行 ordered 区域的时间。 . 是空闲的线程,等待轮到它执行ordered 区域。使用schedule(static,1) 会发生以下情况:

    tid  List of     Timeline
         iterations
    0    0,3,6       ==o==o==o
    1    1,4,7       ==.o==o==o
    2    2,5,8       ==..o==o==o
    

    我相信这两种情况的区别是非常明显的。使用schedule(dynamic),上面的图片或多或少会变得随机,因为分配给每个线程的迭代列表是不确定的。它还会增加额外的开销。仅当每次迭代的计算量不同并且进行计算所花费的时间比使用动态调度所增加的开销要多得多时才有用。

    不要担心编号最小的迭代。它通常被处理到团队中的第一个线程以准备执行代码。

    【讨论】:

    • @Cookie503,请注意,如果块大小太小,则缓存可能会因为丢失数据局部性而变得不那么有用。这可能会比隐含的序列化更严重地损害您的性能。尝试不同的块大小,直到实现最佳加速。明智地使用ordered 循环,并尽可能避开它们,即使它会导致内存占用增加——例如(给定您的特定示例)应使用简单的预分配数组(或其他线程安全的随机访问容器)而不是向量:arr[i] = i;
    • 如果块大小太小,如果数据位于同一缓存行中,我们是否正在考虑错误共享的风险?
    • @WajdanAli 这取决于数据类型及其排列方式,但确实更容易遇到错误共享问题,使用较小的块而不是较大的块。
    • 你能举个例子如何使用语法吗?
    猜你喜欢
    • 2023-03-30
    • 2021-06-01
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    • 2021-06-07
    • 2012-02-18
    • 1970-01-01
    • 2012-07-03
    相关资源
    最近更新 更多