如何并行化循环
How to parallelize a loop?
我在C++上使用OpenMP,我想并行化非常简单的循环。但我不能正确地做到这一点。我一直得到错误的结果。
for(i=2;i<N;i++)
for(j=2;j<N;j++)
A[i,j] =A[i-2,j] +A[i,j-2];
法典:
int const N = 10;
int arr[N][N];
#pragma omp parallel for
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
arr[i][j] = 1;
#pragma omp parallel for
for (int i = 2; i < N; i++)
for (int j = 2; j < N; j++)
{
arr[i][j] = arr[i-2][j] +arr[i][j-2];
}
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
printf_s("%d ",arr[i][j]);
printf("n");
}
你有什么建议我该怎么做吗?谢谢!
串行和并行运行将给出不同的结果,因为在
#pragma omp parallel for
for (int i = 2; i < N; i++)
for (int j = 2; j < N; j++)
{
arr[i][j] = arr[i-2][j] +arr[i][j-2];
}
.....
你更新 arr[i]. 因此,您更改了其他线程使用的数据。 这将导致读写数据竞赛!
这个
#pragma omp parallel for
for (int i = 2; i < N; i++)
for (int j = 2; j < N; j++)
{
arr[i][j] = arr[i-2][j] +arr[i][j-2];
}
永远是悲伤和不可预测的输出的来源。 OpenMP 运行时将为每个线程提供一系列值以供i
,并将它们留给它。 线程更新arr
的相对顺序不会有确定性。 例如,当线程 1 使用 i = 2,3,4,5,...,100
(或其他方式)更新元素,线程 2 使用 i = 102,103,104,...,200
更新元素时,程序不会确定线程 1 是在线程 2 想要使用更新的值之前还是之后更新arr[i,:] = 100
arr
。 您已经编写了具有经典数据竞赛的代码。
您可以通过多种方式解决此问题:
您可以打结,以确保线程以正确的(即顺序)顺序更新arr
。 最终结果将是 OpenMP 程序的运行速度比顺序程序慢。 不要使用此选项。
您可以制作 2 个副本arr
并始终从一个副本更新到另一个副本,然后从另一个副本更新到另一个副本。 类似的东西(非常伪代码)
for ...
{
old = 0
new = 1
arr[i][j][new] = arr[i-2][j][old] +arr[i][j-2][old];
old = 1
new = 0
}
当然,第二种方法以空间换取时间,但这通常是一个合理的权衡。
您可能会发现,向arr
添加额外的平面不会立即加快速度,因为它会破坏拉入缓存的值的空间局部性。 对此进行一些实验,可能使[old]
第一个索引元素而不是最后一个索引元素。
由于更新数组中的每个元素取决于在 2 行/列之外的元素中找到的值,因此您可以有效地将数组像棋盘一样拆分为白色和黑色元素。 您可以使用 2 个线程,每个"颜色"一个,而不会让线程竞相访问相同的数据。 但是,缓存中空间局部性的中断可能会对速度产生不良影响。
如果我遇到任何其他选项,我会编辑它们。
在问题中并行化循环嵌套很棘手,但可行。 Lamport的论文"DO循环的并行执行"涵盖了该技术。 基本上,您必须将 (i,j) 坐标旋转 45 度进入新的坐标系 (k,l),其中 k=i+j 和 l=i-j。
虽然要真正获得加速,但迭代可能必须分组到磁贴中,这使得代码更加丑陋(四个嵌套循环)。
一种完全不同的方法是使用 OpenMP 任务递归解决问题。 递归为:
if( too small to be worth parallelizing ) {
do serially
} else {
// Recursively:
Do upper left quadrant
Do lower left and upper right quadrants in parallel
Do lower right quadrant
}
实际上,算术运算与内存访问的比率非常低,以至于很难从示例中加速。
如果你问一般的并行性,那么另一个可能的答案是矢量化。你可以实现一些相对较差的矢量并行izm(大约2倍加速),没有 更改数据结构和代码库。这可以使用 OpenMP4.0 或 CilkPlus 编译指示 simd 或类似版本(使用 safelen/vectorlength(2))
好吧,你确实有数据依赖性(内部和外部循环),但它属于"WAR"[(读后写)依赖关系子类别,它是使用"omp 并行"按原样"的障碍,但不一定是"编译指示 omp simd"循环的问题。
要使其正常工作,您需要通过OpenMP4或CilkPlus(最近的gcc或Intel编译器)支持编译指示的x86编译器。
- 如何使用 OpenMP 正确并行化 for 循环?
- 嵌套循环 OpenMP 并行化、私有索引还是公共索引?
- 如何并行化增加循环的大小
- 在 C++ 中使用 OpenMP 并行化两个 for 循环不会提供更好的性能
- OpenMP C++:并行化 for 循环的负载不平衡
- 将 for 循环与嵌套的 while 循环并行化时出现 OpenMP 分段错误
- 如何在 OpenACC 中并行化内部具有"min"功能的循环
- 在 C 中并行化嵌套循环的几种方法之间的差异,C++使用 OpenMP
- OpenMP 不在 for 循环中的顺序函数的并行化
- "->"的循环承载依赖性阻止了并行化
- 如何并行化矩阵排序以进行循环
- 使用 c++17 算法并行化简单循环
- 是否可以使用CUDA并行化此嵌套进行循环
- 使用 CUDA 并行化四个或更多嵌套循环
- 如何将openMP的外循环与串行内循环并行化以添加数组
- 与串行相比,openMP 并行化 for 循环的速度更慢
- C++ 2011 : std::thread:并行化循环的简单示例
- 用openmp实现循环并行化的嵌套c++
- OpenMP for循环并行化:我的代码效率很低
- 融合一个三角形循环并行化,计算子指标