【问题标题】:Shared vectors in OpenMPOpenMP 中的共享向量
【发布时间】:2012-04-14 18:48:43
【问题描述】:

我正在尝试并行化我正在使用的程序并得到以下问题。 如果多个线程需要在同一个向量但向量的不同元素上读/写,我会损失性能吗?我有一种感觉,这就是我的程序在并行化后几乎没有变得更快的原因。取以下代码:

#include <vector> 

int main(){

    vector<double> numbers;
    vector<double> results(10);
    double x;

    //write 10 values in vector numbers
    for (int i =0; i<10; i++){
        numbers.push_back(cos(i));  
    } 

#pragma omp parallel for \
    private(x) \
    shared(numbers, results)
        for(int j = 0;  j < 10;  j++){

            x  =  2 * numbers[j]  +  5;  
#pragma omp critical  // do I need this ?
            {
                results[j]  =  x;     
            }
        }

    return 0;

}

显然,实际程序执行的操作要昂贵得多,但这个例子应该 只解释我的问题。那么 for 循环是否可以快速完成并且完全并行,或者不同的线程是否必须相互等待,因为一次只有一个线程可以访问向量编号,尽管它们都在读取向量的不同元素?

与写操作相同的问题:我需要关键的编译指示还是没有问题,因为每个线程都写入向量结果的不同元素? 我对我能得到的每一个帮助都很满意,而且很高兴知道是否有更好的方法来做到这一点(也许根本不使用向量,而是简单的数组和指针等?) 我还读到向量在某些情况下不是线程安全的,建议使用指针:OpenMP and STL vector

非常感谢您的帮助!

【问题讨论】:

    标签: c++ performance stl openmp


    【解决方案1】:

    我想多线程中向量的大多数问题是如果它必须调整大小,那么它将向量的全部内容复制到内存中的一个新位置(分配的更大块),如果你正在访问它这个并行然后你只是试图读取一个已被删除的对象。

    如果您不调整数组的大小,那么我在对向量进行并发读写时从来没有遇到过任何问题(显然,只要我没有写两次相同的元素)

    至于性能提升不足,openmp 临界区会使您的程序减慢到可能与仅使用 1 个线程相同(取决于在该临界区之外实际完成了多少)

    您可以删除临界区语句(考虑到上述条件)。

    【讨论】:

    • 他根本没有调整矢量的大小。
    • @eudoxos 我从代码 sn-p 中意识到,我只是想确保它被提及,特别是因为他提出了 STL 向量在某些条件下不是线程安全的事实跨度>
    • +1:它并没有真正出现在这里,但你必须记住,特定于向量的操作,如追加、调整大小等不是线程安全的,可能会中断。但是只要每个元素只由一个线程编写,只对向量的元素进行操作就可以了。
    • 您好,感谢您的帮助!听到调整大小等问题也很有趣,因为我不仅想知道我的特殊小示例中发生了什么,而且只想了解向量和一般的 OpenMP。我明白我不需要做任何特别的事情,只要每个线程都写在他自己的向量元素中。
    【解决方案2】:

    正是因为多余的关键 sectino,您无法获得加速,因为永远不会同时修改相同的元素。删除关键部分,它会正常工作。

    您也可以使用调度策略,因为如果内存访问不是线性的(在您给出的示例中),线程可能会争夺缓存(在同一缓存行中写入元素)。 OTOH,如果按照您的情况给出了元素的数量并且循环中没有分支(因此它们将以大致相同的速度执行),static,这是 IIRC 的默认值,无论如何应该是最好的。

    (顺便说一句,您可以在循环中声明 x 以避免 private(x) 并且 shared 指令是隐含的 IIRC(我从未使用过)。)

    【讨论】:

    • +1;如果您没有调整大小或附加到向量或有什么向量,那么它只是一个一维数组,OpenMP 非常擅长对数组进行操作。至于静态、私有等,我认为“最佳实践”是使用 default(none) 并使所有内容明确私有或共享,只是为了明确,正如@eudoxos 指出的那样,在并行范围内定义变量部分使它们隐式私有,然后更容易遵循代码。
    • 您好,感谢您的帮助。在循环内声明 x 真的更快(每个线程都会声明它,对吧),而不是在上面的循环之前,还是在性能方面相同,但更好看?内存访问不是线性的是什么意思,为什么会这样?
    • @user1304680:声明是给编译器的,它只是说你想要一块一定大小的内存,并在随后的代码中以某种方式调用它。我怀疑任何体面的、适度优化的编译器都会有所作为。非线性访问:我的意思是从相邻内存区域的线程中随机访问元素。然后 RAM 为 CPU 提供一块内存,它比向量项大。如果 2 个内核访问附近的 RAM 块,它可能在同一个高速缓存行中,然后它们在硬件级别上同步,但这会使速度变慢。在需要之前不要担心。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多