数组真的是随机访问吗 ?


我们都知道,数组是连续分配的内存,对数组的访问是随机的。也就是说不管我访问数组中的哪个元素,应该是相同的常数时间。书上是这么说的,老师也是这么教的,可是在计算机中真的是这样的吗 ?

下面的程序代码对数组分别进行按列和按行访问,为了避免内存初始化等的影响,把两个数组都在全局变量区定义。下面的代码统计了,对两个数组写一遍0的时间。

#include <iostream>
#include <ctime>
using namespace std;

int arrya[1024][1024];
int arryb[1024][1024];
void test()
{

    clock_t start=clock();
    for(int i=0;i<1024;++i)
        for(int j=0;j<1024;++j)
            arrya[i][j]=0;
    clock_t end =clock();
    cout<<"T1:"<<end-start<<endl;

    for(int i=0;i<1024;++i)
        for(int j=0;j<1024;++j)
            arryb[j][i]=0;
    start=clock();
    cout<<"T2:"<<start-end<<endl;
}

int main()
{
    test();
    return 0;
}

看看结果吧:

T1:0
T2:50000

当然,用这个内置c函数统计出来的时间不是很精确,即使多试几次,总是会得到相似的情况,T2远大于T1,为什么呢 ?

这是因为数组在内存中是按列存储的,然后虽然理论上他们是连续分配的,但是由于计算机的缓存、页面调度等机制,按列访问数组时只会有很少的页面调度,而按行访问时会造成颠簸,即会频繁的把相同的页面掉进调出内存。当然了,数组比较小可能页面调度也不是问题,但是同样的理论也应用与CPU的高速缓存,所以不同方式访问时CPU的缓存命中率也不同。这样,访问速度差距会大的惊人。


Haiyang Xu 16 May 2014