专业的编程技术博客社区

网站首页 > 博客文章 正文

加上一个关键字,数组遍历耗时从7.8秒降到1.4秒,这是为什么呢?

baijin 2024-09-12 11:07:34 博客文章 15 ℃ 0 评论

这篇文章代码执行效率的优化思路其实适用于任何编程语言的编程,也许仅仅方式不一样,底层逻辑是一样的,我们这里的讲解以C语言为例,希望大家一定耐心看完,对你优化代码效率一定有启发作用。

后续持续更新系列高质量文章,码字不易,欢迎关注、点赞、收藏。

原始代码

我们经常要做的一个事情就是要进行对矩阵进行操作运算,很多时候我们把矩阵数据存入一个数组里面,不管你要干什么,这里肯定涉及到对数组每一个元素的遍历。这里我们以二维数组为例,我们可以写出以下这样一段代码:

#include <stdio.h>
#include<stdlib.h>
#include<time.h>


int main()
{
    int  row,col;
    time_t start, end;
    time(&start);
    for (row = 0; row <= 15000000; row++){
        for (col = 0; col <= 200; col++){

        }
    }
    time(&end);
    printf("used time:%d s\n",(unsigned int)(end-start));
    return 0;
}

代码非常简单,核心代码其实主要就是两个for循环,两层嵌套按照行与列与去遍历每一个成员,非常简单。

我们下面使用Ubuntu系统下GNU GCC编译器来编译一下生成可执行文件,同时使用time工具来看看这段代码执行耗时是多少(当然,我代码中也写了计算遍历耗时计算相关代码,并打印出来结果,效果都差不多,任意取之)。

可以看到耗时7.8秒,时间非常长,当然这里我模拟比较大的二维矩阵,行数为15000000,列为200,所以矩阵很大,耗时比较长。

优化代码

下面我们对上述简单代码只做一个简单修改,就是在对行列两个循环变量int row,col前面加一个register关键字,变成register int row,col。新代码如下:

#include <stdio.h>
#include<stdlib.h>
#include<time.h>


int main()
{
    register int  row,col;
    time_t start, end;
    time(&start);
    for (row = 0; row <= 15000000; row++){
        for (col = 0; col <= 200; col++){

        }
    }
    time(&end);
    printf("used time:%d s\n",(unsigned int)(end-start));
    return 0;
}

下面如上的方式,我们来看看这个新程序的数组遍历耗时结果。

我们可以看到这个程序耗时仅仅为1.4秒,是原始代码的大约1/6,效率提高6倍,好神奇啊!加了一个关键字register,就效率提升这么多,这是为什么呢?

register关键字是什么?

register是寄存器的意思,C语言变量前面加register,表示是寄存器变量。

这关键字的作用是让编译器将这个变量存储在CPU的寄存器中,而不是放在内存中。如果不加register关键字,那变量就是普通变量,存储于内存RAM中。

优化效果解析

寄存器变量的引入使得计数器 row和col被存储在寄存器中,而不是在内存中。这样做的优势在于,寄存器的访问速度远远快于内存,因此可以显著提高循环的执行效率。

为了更好地理解这一点,让我们来看一下计算机的内存结构层次图:

在这个层次结构中,寄存器位于顶部,是最快速的存储器,但容量最小。高速缓存相对较快,但容量更大。主存(RAM)速度较慢,但容量更大,而辅助存储设备(硬盘等)则是最慢但最大容量的存储器。

通过将变量存储在寄存器中,我们可以减少对相对较慢的主存的访问,从而提高程序的整体性能。在上面的数组的遍历循环中,这种优化特别重要,尤其是较多次循环,因为它涉及对变量row和col的频繁访问,而这些变量如果能够存储在寄存器中,就能够更快速地被访问和处理。

循环中的每次迭代都需要对i进行递增和求和操作,而这些操作现在都可以在寄存器中进行,而无需频繁地与内存交互。这减少了内存总线的压力,减小了访问延迟,从而加速了代码的执行。

这也说明了寄存器变量并不仅仅是一种语法上的优化,而是直接与计算机体系结构的层次有关,通过合理利用寄存器,我们可以充分发挥硬件的性能潜力。

需要注意的是,寄存器变量并不总是带来性能提升,因为寄存器的数量是有限的,而编译器也会根据上下文进行变量的寄存器分配。因此,程序员在使用寄存器变量时应该谨慎,根据具体情况权衡性能提升和编程规范。

在实际项目中,可以通过编译器提供的性能分析工具,如GCC的 -O2 或 -O3 选项,来进一步优化代码并评估性能提升效果。

优化通用思路总结

我们这里不是为了讲寄存器变量,重点是让大家理解一个优化代码效率的通用思路:

对于访问次数非常频繁的数据,在条件允许的前提下,建议将该数据尽量放到访问速度最快的硬件存储介质存储,从而从底层硬件读写上提高效率,最终提高代码执行效率。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表