程序性能优化:a[i][j]与a[j][i]

通常我们写代码,对于数组的操作都是行优先,即一行一行地进行处理,如:

for(int i=0;i<N;i++)
    for(int j=0;j<N;j++)
        a[i][j]=...;

但是如果写成列优先,性能会有不同吗?

for(int i=0;i<N;i++)
    for(int j=0;j<N;j++)
        a[j][i]=...;  //注意,j在前i在后,即列优先

做一个小实验,对一个大数组进行操作,看看程序的运行情况。有如下代码:

#include<time.h>
#include<iostream>
using namespace std;

#define SIZE 10000
//因为栈默认大小为1M左右,将数组声明为全局变量,避免栈溢出
int arr[SIZE][SIZE]={0};

int main(){
    int temp=0;

    clock_t start1=clock();  //行优先操作--开始
    for(int i=0;i<SIZE;i++)
        for(int j=0;j<SIZE;j++)
            temp=arr[i][j];
    clock_t finish1=clock();  //行优先操作--结束
    cout<<"行优先操作用时: "<<(double)(finish1-start1)<<"ms"<<endl;

    clock_t start2=clock();  //列优先操作--开始
    for(int i=0;i<SIZE;i++)
        for(int j=0;j<SIZE;j++)
            temp=arr[j][i];
    clock_t finish2=clock();  //列优先操作--结束
    cout<<"列优先操作用时: "<<(double)(finish2-start2)<<"ms"<<endl;

    cin>>temp;  //暂停以便于观看结果
    return 0;
}

程序的运行结果://可能有误差,但不影响大体的结果

SIZE大小行优先用时(ms)列优先用时(ms)倍数(列/行)
10000-
500111
1000541
200024301.25
50001832741.5
1000053114312.7
200001978107805.5
30000出错-_-!--

通过对各种不同SIZE的运行结果对比,发现对于小数组(SIZE<=2000),两种方式用时差不多。而对于大数组,差距随着SIZE增大,列/行 用时倍数也增大。
是什么导致了这样的结果呢?这就涉及到了局部性原理。

《深入理解计算机系统》:一个编写良好的计算机程序常常具有良好的局部性。它们倾向于引用临近于其他最近引用过的数据项的数据项,
或者最近引用过的数据项本身。这种倾向性被称为局部性原理(principle of locality)。---P401
局部性通常有两种不同的形式:时间局部性和空间局部性。
时间局部性:被引用过一次的存储器位置很可能在不远的将来再被多次引用。
空间局部性:若某一存储器位置被引用了一次,则程序很可能在不远的将来引用附近的一个存储器位置。

//此处需要一点高速缓存Cache的知识,参考《计算机组成原理》
高速缓存存储器Cache容量有限,数组是按行载入Cache中的。假设每次载入400个字节,即100个数组元素。

行优先操作:第一行操作,a[0][0]不命中,载入a[0][0]~a[0][99]到Cache中,之后的a[0][1]、a[0][2]…a[0][99]命中。接着a[0][100]不命中,将a[0][100]~a[0][199]到Cache中,以此类推。整体命中率约为99%。CPU读Cache所需的时钟周期比读内存少很多,因此程序性能高。

列优先操作:第一列操作,a[0][0]不命中,载入a[0][0]~a[0][99]到Cache中,之后的a[1][0]不命中,载入a[1][0]~a[1][99]到Cache中,每次载入的内容都只读了第一个。Cache容量有限,当Cache中内容满时,为了载入新的内容,需要覆盖掉已有的内容。

由此可知,当数组很小时,Cache容量足够存储整个数组,不存在载入覆盖,因此两者运行时间差不多。当数组很大时,导致了不同程度的载入覆盖,从而两者运行时间比值随着SIZE增大而增大。

看似微小的改动,都会导致程序性能的巨大差距,因此在编程的时候,结合各方面的知识分析程序性能,是必不可少的。

在最后推荐一本书—《深入理解计算机系统》,英文名是 Computer Systems: A Programmer’s Perspective。此书从程序员的视角详细阐述计算机系统的本质概念,并展示这些概念如何实实在在地影响应用程序的正确性、性能和实用性。但是需要一小部分计算机组成原理的知识,以及对C和C++有一定的了解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值