为什么 OpenMP 不加速基本循环?
Why a basic loop isn't accelerated by OpenMP?
我有一个基本循环:
int i, n=50000000;
for (i=0 ; i<n ; i++)
{
register float val = rand()/(float)RAND_MAX;
}
我想用OpenMP加速。我之前设置:
omp_set_dynamic(0);
omp_set_num_threads(nths);
带nths=4
最后一个循环是:
int i, n=50000000;
#pragma omp parallel for firstprivate(n) default(shared)
for (i=0 ; i<n ; i++)
{
register float val = rand()/(float)RAND_MAX;
}
非并行循环需要1.12秒执行,并行循环需要21.04秒(根据我的linux优先级进程,它可能会变化很大)。我在一个x86平台上,有Ubuntu和4个CPU,每个CPU有1个线程。我使用-fopenmp
标记的g++
(我需要它)进行编译,并使用库-lgomp
为什么OpenMP不加速这个基本循环?
编辑:
关于答案,我将循环的内部更改为:
for (i=0 ; i<n ; i++)
{
a[i]=i;
b[i]=i;
c[i]=a[i]+b[i];
}
带有n=500000
和pragma:
#pragma omp parallel for firstprivate(n) default(shared) schedule(dynamic) num_threads(4)
我还更改了代码,只使用gcc
,我也遇到了同样的问题:
With 1 Thread
Test ms = 0.003000
Test Omp ms = 19.695000
With 4 Threads
Test ms = 0.003000
Test Omp ms = 240.990000
第2版:
在使用OpenMP时,我改变了测量时间的方式。与clock()
函数不同,我使用了omp_get_wtime()
函数,结果要好得多。
我在系统中快速运行了您的代码。首先,在阵列添加的情况下,您的50M几乎不足以显示胜利,但如果OpenMP设置正确,它确实可以。
在您的情况下,schedule(dynamic)
正在杀死您——它告诉编译器在运行时将工作分配给团队。如果你不能预先确定你的工作量,这是有意义的——但在这种情况下,它是完全可以预测的,因为每次迭代的工作量完全相同。
在编辑了您的示例(见下文)并在超线程CPU上运行后,我得到了以下结果,所有内核都固定在最低频率。我使用gcc 4.9.3:编译
time ./testseq && time ./testpar
real 0m0.576s
user 0m0.504s
sys 0m0.072s
real 0m0.285s
user 0m0.968s
sys 0m0.123s
正如您所看到的,real
值,即"wallclock时间",大约是一半。由于线程启动和关闭,user
时间增加。
如果我添加schedule(dynamic)
子句:,则并行化的结果会发生显著变化
real 0m4.181s
user 0m14.886s
sys 0m1.283s
所有额外的工作负载都花在了完成少量工作并寻找下一批的线程上。这需要一个锁——这会扼杀你的第二个例子。请仅在出现负载平衡问题时使用schedule(dynamic)
,因为每个迭代器的工作量变化很大。
为了充分披露,我运行了以下完整的源代码:
CXXFLAGS=-std=c++11 -I. -Wall -Wextra -g -pthread
all: testseq testpar
testpar: test.cpp
${CXX} -o $@ $^ -fopenmp ${CXXFLAGS}
testseq: test.cpp
${CXX} -o $@ $^ ${CXXFLAGS}
clean:
rm -f *.o *~ test
和test.cpp
:
#include <omp.h>
constexpr int n=50*1000*1000;
float a[n];
float b[n];
float c[n];
int main(void) {
#pragma omp parallel for schedule(dynamic)
for (int i=0 ; i<n ; i++) {
a[i]=i;
b[i]=i;
c[i]=a[i]+b[i];
}
}
请注意,我还删除了您的parallel for
的其他条款——您不需要它们。
rand()
根本不是线程安全函数。内部有一个PRNG具有状态,因此在没有同步的情况下无法由多个线程调用。使用不同的PRNG(C++11有很多,Boost也是),每个线程使用一个生成器,不要忘记用不同的种子值对它们进行种子设定(小心time(NULL)
)。
更新
由于线程创建的开销,500k的CCD_ 18可能太小而无法获得任何加速。你能用n
设置为500M来测试吗?此外,没有OpenMP的时间低得令人怀疑(对于如此低的n
可能不是这样)。循环后,您将如何处理a
、b
和c
阵列?如果没有,编译器可以优化顺序代码中的整个循环对这些数组执行一些操作,例如,打印出它们的总和(在测量部分之外)。
- 如何循环打印顶点结构
- 如何在C++中从两个单独的for循环中添加两个数组
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 正在尝试了解输入验证循环
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 加速C++练习2.4
- 循环后如何继续阅读
- Ardunio UNO解决了多个重叠的定时器循环
- Eigen如何在容器循环中干净地附加矩阵
- 在某些循环内使用vector.push_back时出现分段错误
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 使用.push_back加速循环
- C :使用goto加速循环
- 为什么 OpenMP 不加速基本循环?
- 对于循环在 gcc -O3 使用 OpenMP 优化后不会加速
- 如何使用MySQL将c++for循环代码加速到查询中
- 多线程c++程序加速一个求和循环
- 为球体的体积加速代码(嵌套while循环)
- 如何在php中通过数组加速循环
- OpenMP并行循环加速问题