我正在努力平行我正在使用的程序并得到以下问题。 如果多个线程需要在同一个向量上读取/写入但向量的不同元素,我会失去性能吗?我感觉这就是我的程序在平行化时几乎没有得到更快的原因。请使用以下代码:
#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
非常感谢你的帮助!
答案 0 :(得分:7)
我认为多线程中向量的大多数问题都是如果它必须调整大小,然后它将向量的整个内容复制到内存中的新位置(更大的已分配块),如果您正在访问它这个并行然后您只是尝试读取已删除的对象。
如果你没有调整数组的大小,那么我从来没有遇到过对向量的并发读写问题(显然,只要我没有写两次相同的元素)
至于缺乏性能提升,openmp临界区将使你的程序速度降低到可能只是使用1个线程(取决于在关键部分之外实际完成的程度)
您可以删除关键部分声明(考虑上述条件)。
答案 1 :(得分:5)
由于关键的sectino是多余的,因此不会加速,因为相同的元素永远不会同时被修改。删除关键部分,它将正常工作。
您也可以使用调度策略,因为如果内存访问不是线性的(在您给出的示例中),则线程可能会争用缓存(在同一缓存行中写入元素)。 OTOH如果在你的情况下给出了元素的数量并且循环中没有分支(因此它们将以大约相同的速度执行),static
(默认为IIRC)应该最好地工作。
(顺便说一句,你可以在循环中声明x
以避免private(x)
而隐含shared
指令是IIRC(我从未使用过它)。)