我发现有时将一个循环划分为两个或更多
会更快for (i=0; i<AMT; i++) {
a[i] += c[i];
b[i] += d[i];
}
||
\/
for (i=0; i<AMT; i++) {
//a[i] += c[i];
b[i] += d[i];
}
for (i=0; i<AMT; i++) {
a[i] += c[i];
//b[i] += d[i];
}
在我的桌面上,win7,AMD Phenom(tm)x6 1055T,双循环版本运行速度更快,时间缩短了1/3。
但如果我正在处理作业,
for (i=0; i<AMT; i++) {
b[i] = rand()%100;
c[i] = rand()%100;
}
将b和c的赋值分成两个循环并不比在一个循环中快。
我认为操作系统使用一些规则来确定是否有某些代码 可以由多个处理器运行。
我想问一下我的猜测是否正确,如果我是对的,那么多个处理器会有什么样的规则或场合 是否自动(没有线程编程)用于加速我的程序?
答案 0 :(得分:4)
您的编译器可能是vectorizing更简单的循环。在汇编程序输出中,您会将此视为使用SIMD指令(如Intel's SSE)编译的程序,以处理比一次一个数字更大的数据块。自动矢量化是一个难题,而且编译器无法对同时更新a
和b
的循环进行矢量化是合理的。这可以部分解释为什么将复杂循环分解为两个会更快。
在“赋值”循环中,每次调用rand()
都取决于先前调用的输出,这意味着向量化本质上是不可能的。将循环分成两个并不会使它受益于第一种情况下的SIMD指令,因此您不会看到它运行得更快。查看编译器生成的汇编代码将告诉您编译器执行了哪些优化以及使用了哪些指令。
即使编译器正在向量化循环,程序也不会使用多个CPU或线程;没有并发。会发生的是,一个CPU能够在多个数据点上并行运行单个执行线程。并行和并发编程之间的区别是微妙但重要的。
缓存局部性也可以解释为什么将第一个循环分成两个使得它运行得更快,但不是为什么将“赋值”循环分成两个不会。 “赋值”循环中的b
和c
可能足够小,以便它们适合缓存,这意味着循环已经具有最佳性能并且进一步打破它不会带来任何好处。如果是这种情况,那么使b
和c
更大将迫使循环开始废弃缓存并将循环分成两个会产生预期的好处。
答案 1 :(得分:2)
优化由编译器(http://en.wikipedia.org/wiki/Loop_optimization)完成。 如果您使用GCC,请查看此页面http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html以获取可用优化规则列表。
另一方面,看到你正在使用rand()函数,这会消耗大量的CPU时间。
答案 2 :(得分:0)
我想问一下我的猜测是否正确,如果我是对的,那么多个处理器将自动(没有线程编程)用于加速我的程序的规则或场合是什么?
不,猜测不对。在所有三种情况下,代码都在一个核心上运行。
由于某些其他原因,将第一个循环分成两个使得它更快。也许您的编译器能够生成更好的代码,或者CPU可以更容易地预取正确的数据等。如果不分析生成的机器代码,很难说清楚。