如何在C++;让代码更快? 我试图在C++中使用并行化。
下面是我编写的示例代码 我听说我需要足够数量的N才能使并行化工作 所以我提出了三维数组。(我增加了“堆栈保留大小”的大小以运行下面的代码。) 我用“chrono”来测量经过的时间 但在这段代码中,并行化实际上会使代码变慢 所以我想知道发生这种情况的原因是什么 这是因为运行并行化的固定成本与我这里的“i”的数量相比仍然很大吗如何在C++;让代码更快? 我试图在C++中使用并行化。,c++,C++,下面是我编写的示例代码 我听说我需要足够数量的N才能使并行化工作 所以我提出了三维数组。(我增加了“堆栈保留大小”的大小以运行下面的代码。) 我用“chrono”来测量经过的时间 但在这段代码中,并行化实际上会使代码变慢 所以我想知道发生这种情况的原因是什么 这是因为运行并行化的固定成本与我这里的“i”的数量相比仍然很大吗 int main() { omp_set_num_threads(8); double AAA[1000][1000][10]; double A[1
int main() {
omp_set_num_threads(8);
double AAA[1000][1000][10];
double A[1000];
fill(&AAA[0][0][0], &AAA[0][0][0] + sizeof(AAA) / sizeof(AAA[0][0][0]), 1);
fill(&A[0], &A[0] + sizeof(A) / sizeof(AAA[0]), 2);
system_clock::time_point start = system_clock::now();
#pragma omp parallel for private(A)
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 1000; j++) {
for (int k = 0; k < 10; k++) {
AAA[i][j][k] = A[i] + A[j] + A[k];
}
}
}
system_clock::time_point end = system_clock::now();
std::chrono::duration<double> sec = end - start;
cout << sec.count() << endl;
}
intmain(){
omp_设置_数量_线程(8);
双AAA[1000][1000][10];
双A[1000];
填充(&AAA[0][0][0],&AAA[0][0]+sizeof(AAA)/sizeof(AAA[0][0][0]),1);
填充(&A[0],&A[0]+sizeof(A)/sizeof(AAA[0]),2);
系统时钟::时间点开始=系统时钟::现在();
#pragma omp并行专用(A)
对于(int i=0;i<1000;i++){
对于(int j=0;j<1000;j++){
对于(int k=0;k<10;k++){
AAA[i][j][k]=A[i]+A[j]+A[k];
}
}
}
系统时钟::时间点结束=系统时钟::现在();
标准::计时::持续时间秒=结束-开始;
你的问题是内存不足。
这意味着程序在内存/缓存之间移动数据的时间比实际计算要长得多。
事实上,计算只包括两个加法。
您可以增加数组(当然是在堆上,而不是在堆栈中),内存传输和计算时间之间的比率将是相同的,甚至更糟(因为数据不完全适合缓存)。
从处理器的角度来看,让八个内核等待内存传输(写缓冲区)并没有比只有一个内核等待更大的帮助(除非您有不同的内存控制器,并且在NUMA系统上物理内存使用的良好平衡)
如果您希望通过并行化观察增益,则需要增加使用相同数据量执行的计算量。
下面是你的例子修改了一个非常愚蠢的方式,只是为了观察这个增益(4.365到0.652153秒在我的系统上)
/**
g++-std=c++17-o prog_cpp prog_cpp.cpp\
-pedantic-Wall-Wextra-Wconversion-Wno符号转换\
-O3-march=本地-fopenmp
**/
#包括
#包括
#包括
#包括
#包括
int
main()
{
constexpr auto ni=2000,nj=ni,nk=100;
自动AAA=std::vector(ni*nj*nk,1.0);
自动A=标准::向量(ni,2.0);
#如果定义了OPENMP
omp_设置_数量_线程(8);
#恩迪夫
const auto start=std::chrono::system_clock::now();
#pragma-omp并行
对于(自动i=0;i您的问题是内存受限。
这意味着程序在内存/缓存之间移动数据的时间比实际计算要长得多。
事实上,计算只包括两个加法。
您可以增加数组(当然是在堆上,而不是在堆栈中),内存传输和计算时间之间的比率将是相同的,甚至更糟(因为数据不完全适合缓存)。
从处理器的角度来看,让八个内核等待内存传输(写缓冲区)并没有比只有一个内核等待更大的帮助(除非您有不同的内存控制器,并且在NUMA系统上物理内存使用的良好平衡)
如果您希望通过并行化观察增益,则需要增加使用相同数据量执行的计算量。
下面是你的例子修改了一个非常愚蠢的方式,只是为了观察这个增益(4.365到0.652153秒在我的系统上)
/**
g++-std=c++17-o prog_cpp prog_cpp.cpp\
-pedantic-Wall-Wextra-Wconversion-Wno符号转换\
-O3-march=本地-fopenmp
**/
#包括
#包括
#包括
#包括
#包括
int
main()
{
constexpr auto ni=2000,nj=ni,nk=100;
自动AAA=std::vector(ni*nj*nk,1.0);
自动A=标准::向量(ni,2.0);
#如果定义了OPENMP
omp_设置_数量_线程(8);
#恩迪夫
const auto start=std::chrono::system_clock::now();
#pragma-omp并行
对于(auto i=0;我想这是一个愚蠢的问题,但如果我只是增加堆栈的大小并保存每个进位堆栈而不是堆,会有问题吗?如果我使用堆栈而不是堆,并行化会不会行不通?我已经用ni=1000和nk=100更改了你的示例。当我使用“release”时,它看起来像结果与“#pragma omp parallel for”相同,没有“#pragma omp parallel for.”0.37秒。但是,如果使用“debug”,我会看到两个结果之间的一些差异。因此我想知道并行化是否只在debug中起作用?@ChangseokMa堆栈空间通常非常有限(千字节到几兆字节,取决于系统),因此,为了避免由于堆栈溢出而导致崩溃;^)我们通常在堆中分配大量数据(无论问题是什么,并行化与否)。这不会改变并行化的任何内容。@ChangseokMa关于您系统上的调试/发布问题,我没有任何线索……在我的系统上,我在启用优化的情况下进行了测试(请参见命令行)在优化后,你的编译器在优化<代码> > <代码> >和数学调用,使得并行化没有可测量的效果。谢谢。我有一个附加的问题……如果我使用Ni=2000,NK=100当你上传时。不知为什么我的C++不工作,所以我需要把大小缩小到Ni=1000和NK=1。0.据我所知,vector不需要动态分配权…?那么这只是我的计算机内存问题吗?谢谢你的评论。我认为这是一个愚蠢的问题,但如果我只是增加堆栈的大小,并在堆栈中保存每个进位而不是堆,会有问题吗?如果我使用堆栈而不是堆,并行化不会进行吗去工作吗
/**
g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
-pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
-O3 -march=native -fopenmp
**/
#include <iostream>
#include <chrono>
#include <vector>
#include <cmath>
#include <omp.h>
int
main()
{
constexpr auto ni=2000, nj=ni, nk=100;
auto AAA=std::vector<double>(ni*nj*nk, 1.0);
auto A=std::vector<double>(ni, 2.0);
#if defined _OPENMP
omp_set_num_threads(8);
#endif
const auto start=std::chrono::system_clock::now();
#pragma omp parallel for
for(auto i=0; i<ni; ++i)
{
for(auto j=0; j<nj; ++j)
{
for(auto k=0; k<nk; ++k)
{
const auto idx=i*(nj*nk)+j*nk+k;
if(j<k)
{
AAA[idx]+=std::sqrt(A[i])+std::log(A[j]);
}
else
{
AAA[idx]+=std::log(A[j])+std::cos(A[k]);
}
}
}
}
const auto end=std::chrono::system_clock::now();
const auto duration=std::chrono::duration<double>{end-start};
std::cout << duration.count() << '\n';
return 0;
}