我最初的直觉是每个数组循环会更好,因为数据局部性将有助于缓存。
将所有数组放在一个循环中会污染缓存(在处理第一个数组时,缓存将(部分)由该数组的某些元素填充,但在下一行代码中,您将需要数据第二个数组和缓存将无法提供帮助。
两种情况下的理论复杂度保持不变。
但是,这取决于您拥有的数组数量(我现在不是说连续的)。必须一次又一次地从头开始循环可以超过每个循环一个数组的方法可以提供的缓存加速,如下所示:
Georgioss-MacBook-Pro:~ gsamaras$ cat bigloop.c
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#define N 100000
typedef struct timeval wallclock_t;
void wallclock_mark(wallclock_t *const tptr);
double wallclock_since(wallclock_t *const tptr);
// gcc -Wall -O3 bigloop.c -o bigloop
int main(void)
{
int a[N], b[N], c[N], d[N], e[N], i;
wallclock_t t;
double s;
wallclock_mark(&t);
for(i = 0; i < N; ++i)
{
a[i] = i * 10 + (i - 2);
b[i] = i * 9 + (i - 3);
c[i] = i * 8 + (i - 1);
d[i] = i * 11 + (i - 5);
e[i] = i * 5 + (i - 0);
}
s = wallclock_since(&t);
printf("Populating took %.9f seconds wall clock time.\n", s);
wallclock_mark(&t);
for(i = 0; i < N; ++i)
{
a[i] = e[i] + (i - 1);
b[i] = d[i] + (i + 3);
c[i] = a[i] - (i + 2);
d[i] = b[i] + (i - 2);
e[i] = a[i] + (i - 4);
}
s = wallclock_since(&t);
printf("Load/write took %.9f seconds wall clock time.\n", s);
return 0;
}
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#define N 100000
typedef struct timeval wallclock_t;
void wallclock_mark(wallclock_t *const tptr);
double wallclock_since(wallclock_t *const tptr);
int main(void)
{
int a[N], b[N], c[N], d[N], e[N], i;
wallclock_t t;
double s;
wallclock_mark(&t);
for(i = 0; i < N; ++i)
a[i] = i * 10 + (i - 2);
for(i = 0; i < N; ++i)
b[i] = i * 9 + (i - 3);
for(i = 0; i < N; ++i)
c[i] = i * 8 + (i - 1);
for(i = 0; i < N; ++i)
d[i] = i * 11 + (i - 5);
for(i = 0; i < N; ++i)
e[i] = i * 5 + (i - 0);
s = wallclock_since(&t);
printf("Populating took %.9f seconds wall clock time.\n", s);
wallclock_mark(&t);
for(i = 0; i < N; ++i)
a[i] = e[i] + (i - 1);
for(i = 0; i < N; ++i)
b[i] = d[i] + (i + 3);
for(i = 0; i < N; ++i)
c[i] = a[i] - (i + 2);
for(i = 0; i < N; ++i)
d[i] = b[i] + (i - 2);
for(i = 0; i < N; ++i)
e[i] = a[i] + (i - 4);
s = wallclock_since(&t);
printf("Load/write took %.9f seconds wall clock time.\n", s);
return 0;
}
我省略了时间测量代码,我有 here。结果是:
Georgioss-MacBook-Pro:~ gsamaras$ ./bigloop
Populating took 0.000581000 seconds wall clock time.
Load/write took 0.000178000 seconds wall clock time.
Georgioss-MacBook-Pro:~ gsamaras$ ./loop
Populating took 0.001092000 seconds wall clock time.
Load/write took 0.000285000 seconds wall clock time.
您可以看到在填充数组时,all-arrays-in-one-loop 获得了一个数量级的加速。此外,处理它们的速度也更快!
所以,如果我是你,我会同时实施这两种方法并衡量时间! =)
PS:不要成为过早优化的受害者。如果您有一个想要优化的项目,请分析您的代码以找到瓶颈并专注于此!