首页 > 解决方案 > 在 OpenMP 中读取/写入共享向量会减慢程序速度

问题描述

我正在努力将 OpenMP 用于分片向量。在我的真实代码中,我有一个存储数组的向量,我希望使用 OpenMP 来加速一个 for 循环,我必须在其中访问向量内的所有这些元素并计算与截止范围内的所有其他元素的交互。这意味着,在向量的不同块中,交互的计算是独立的。并且计算是一个方向和周期性的,从第一个元素开始,到最后一个元素与前几个元素相互作用。我只是希望使用两个线程来测试可行性,并将工作负载分为两部分,我认为它们是相互独立的。

但是单核的仿真时间是:real 0m2.417s user 0m2.149s sys 0m0.011s

多线程是:真正的 0m4.490s 用户 0m8.371s sys 0m0.024s

更新

感谢人们已经给了我一些建议,我非常感谢。我想给出我的代码的更多细节:所以有一个向量有 100 个元素,每个元素将与右手相邻的 9 个元素进行计算。这很棘手,因为实际上这项工作可以分为 10 种独立的工作,所以我天真地认为这适合并行计算,但如果线程没有很好地组织起来,很可能会出现竞态条件. 那么,我如何具体说明使用 OpenMP 的工作负载,以确保同时不同的线程正在读取/写入向量的不同部分?

#include <stdio.h>
#include <omp.h> 
#include <vector>
#include <array>
#include <iostream>
using namespace std;

auto k = 50000;
auto cutOff = k/10;

void testFunc(vector<int> &positions){
#pragma omp parallel for num_threads(2) schedule(static, k/2)
    for (int i = 0; i< k ; i++){
        for (int j = i; j<i+cutOff; j++){
            j=(j<=k?j:j-k);
                positions[i]+=1;
                positions[j]-=1;
        }
    }
}

int main()
{
    vector<int> pos;
    pos.resize(k);
    for (int i = 0; i<pos.size(); i++){
            pos[i]=rand() % 100;
        }

    printf("first value = %d\n", pos[0]);
    testFunc(pos);
    printf("last value = %d\n", pos[0]);
}

标签: c++vectoropenmp

解决方案


正如您正确观察到的那样,作品可以分为独立的块或“部分”,例如:

void testFunc(vector<int> &positions){
    int numSections = cutOff;
    for (int section = 0; section < numSections; ++section) {
#pragma omp parallel for schedule(static)
        for (int i = section; i < k ; i += cutOff) {
            for (int offset = 0; offset < cutOff; ++offset) {
                int j = i + offset;
                if (j >= k)
                    j -= k;
                positions[i] += 1;
                positions[j] -= 1;
            }
        }
    }
}

https://godbolt.org/z/qdC0Rw

请注意,这只有k在实际上可以被cutOff!整除时才能正常工作。(考虑k = 11cutOff = 10。)

cutOff如果很大(例如,如果它是 的 10% ),那么启动许多并行部分看起来会产生很多开销k,但这更多是因为算法本身是二次的(它修改2 * k * cutOff = 0.2 * k * k了元素)。因此,如果您k的规模很大,那么并行化仍然很值得。


推荐阅读