我有一个带有多个For循环的c ++程序;每个运行大约500万次迭代。是否有任何命令我可以使用g ++来生成.exe将使用多个核心;即在第一个核心上运行第一个For循环,同时在第二个核心运行第二个For循环?我已经尝试过-O3和-O3 -ftree-vectorize,但在这两种情况下,我的cpu使用率仍然仅在25%左右徘徊。
编辑: 这是我的代码,以防万一。我基本上只是制作一个程序来测试我的计算机的速度功能。
#include <iostream>
using namespace std;
#include <math.h>
int main()
{
float *bob = new float[50102133];
float *jim = new float[50102133];
float *joe = new float[50102133];
int i,j,k,l;
//cout << "Starting test...";
for (i=0;i<50102133;i++)
bob[i] = sin(i);
for (j=0;j<50102133;j++)
bob[j] = sin(j*j);
for (k=0;k<50102133;k++)
bob[k] = sin(sqrt(k));
for (l=0;l<50102133;l++)
bob[l] = cos(l*l);
cout << "finished test.";
cout << "the 100120 element is," << bob[1001200];
return 0;
}
答案 0 :(得分:7)
最明显的选择是使用OpenMP。假设您的循环是一个非常容易并行执行多个迭代的循环,您可能只需添加:
#pragma openmp parallel for
...紧接在循环之前,让它并行执行。编译时还需要添加-fopenmp
。
根据循环的内容,这可能会提供近乎线性的加速,从而在某种程度上减慢代码速度。在后一种情况下(减速或最小加速),你可以用OpenMP做其他事情来帮助加快速度,但是至少不知道代码本身,你很难猜测该做什么或改进什么能够达到最大值。
您获得的其他建议(“使用线程”)可能是合适的。 OpenMP基本上是一种将线程用于特定类型的并行代码的自动方式。对于你描述的情况(并行执行循环的多次迭代),OpenMP通常是首选的 - 它实现起来相当简单,并且可能会提供更好的性能,除非你非常了解多线程和/或花费很多努力并行化代码。
编辑:
您在问题中提供的代码可能不会受益于多个线程。问题是在将结果写入内存之前,它对每个数据项执行的计算非常少。即使是单核也可以足够快地进行计算,总速度将受到内存带宽的限制。
为了从多个线程中获得一些真正的好处,您可能希望编写一些代码来执行更多计算,而不仅仅是读取和写入内存。例如,如果我们将您的计算合并在一起,并在一个项目上完成所有这些计算,那么对结果求和:
double total = 0;
for (int i = 0; i < size; i++)
total += sin(i) + sin(i*i) + sin(sqrt(i)) + cos(i*i);
添加编译指示:
#pragma omp parallel for reduction(+:total)
...就在for
循环之前,我们很有可能看到执行速度大幅提升。没有OpenMP,我会得到这样的时间:
Real 16.0399
User 15.9589
Sys 0.0156001
...但是在编译时启用了#pragma
和OpenMP,我得到这样的时间:
Real 8.96051
User 17.5033
Sys 0.0468003
所以,在我的(双核)处理器上,时间从16秒减少到9秒 - 不是快两倍,但非常接近。当然,您获得的许多改进将取决于您可用的核心数量。例如,在我的另一台计算机上(使用Intel i7 CPU),我得到了相当大的改进,因为它有更多内核。
没有OpenMP:
Real 15.339
User 15.3281
Sys 0.015625
...并使用OpenMP:
Real 3.09105
User 23.7813
Sys 0.171875
为了完整性,这是我使用的最终代码:
#include <math.h>
#include <iostream>
static const int size = 1024 * 1024 * 128;
int main(){
double total = 0;
#pragma omp parallel for reduction(+:total)
for (int i = 0; i < size; i++)
total += sin(i) + sin(i*i) + sin(sqrt(i)) + cos(i*i);
std::cout << total << "\n";
}
答案 1 :(得分:2)
编译器无法判断循环内的代码是否可以在多个内核上安全地执行。如果要使用所有核心,请使用线程。
答案 2 :(得分:0)
C ++ 11获得了对threading的支持,但c ++编译器不会/不能自己做任何线程。
答案 3 :(得分:0)
使用主题或进程,您可能希望查看OpenMp
答案 4 :(得分:0)
正如其他人指出的那样,您可以手动使用线程来实现此目的。您可以查看libdispatch(aka。GCD)或Intel's TBB等库来帮助您以最少的痛苦来完成这项工作。
您提到的-ftree-vectorize
选项用于定位CPU上的SIMD矢量处理器单元,例如ARM的NEON或Intel的SSE。生成的代码不是线程并行的,而是使用单个线程并行操作。
上面发布的代码示例非常适合SIMD系统上的并行性,因为每个循环的主体在前一次迭代中非常明显地没有依赖性,并且循环中的操作是线性的。
至少在某些ARM Cortex A系列系统上,您可能需要接受稍微降低的准确度才能获得全部好处。