C语言表示程序的局部性原理,局部性原理

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

在这篇文章的开头,我们先不讲什么是局部性原理。我们直接来看一段代码和它的执行结果。

行优先遍历1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32#include

using namespace std;

int arr[10000][10000];

int (int argc, char const *argv[])

{

int sum = 0;

for (int i = 0; i < 10000; i++) {

for (int j = 0; j < 10000; j++) {

arr[i][j] = 0;

}

}

clock_t begin = clock();

for (int i = 0; i <10000; i++) {

for (int j = 0; j < 10000; j++) {

sum += arr[i][j];

}

}

clock_t end = clock();

cout<

return 0;

}

列优先遍历1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32#include

using namespace std;

int arr[10000][10000];

int (int argc, char const *argv[])

{

int sum = 0;

for (int i = 0; i < 10000; i++) {

for (int j = 0; j < 10000; j++) {

arr[i][j] = 0;

}

}

clock_t begin = clock();

for (int j = 0; j <10000; j++) {

for (int i = 0; i < 10000; i++) {

sum += arr[i][j];

}

}

clock_t end = clock();

cout<

return 0;

}

分析

我们对比什么的两个代码,可以发现结果是不同的咦( ′◔ ‸◔`)?看看代码都是把这10000 * 10000个数字累加起来呀,目的不都是一样的吗?

蓝儿,这段代码唯一不同的地方就是循环相加的那部分,外循环和内循环的i和j对换了一下位置。那么这样做的影响是什么呢?

这里我们引入一个局部性的概念。

局部性

何为局部性?

局部性按照我个人的简单理解就是把一些内容缓存起来。以供后面需要的时候使用。

局部性通常有两种不同的形式:时间局部性和空间局部性。在一个具有良好时间局部性的程序中,被引用过一次的存储器位置很可能在不远的将来被多次引用。在一个具有良好空间局部性的程序中,如果一个存储器位置被引用了一次,那么程序很可能在不远的将来引用附近的一个存储器位置。

在硬件层,局部性原理允许计算机设计者通过引入称为高速缓存存储器的小而快速的存储器来保存最近被引用的指令和数据项,从而提高对主存的访问速度。在操作系统级,局部性原理允许系统使用主存作为虚拟地址空间最近被引用块的高速缓存。类似地,操作系统用主存来缓存磁盘文件系统中最近被使用的磁盘块。

Web浏览器将最近被引用的文档放在本地磁盘上,利用的就是时间局部性。大量的Web服务器将最近被请求的文档放在前端磁盘高速缓存中,这些缓存能满足对这些文档的请求,而不需要服务器的任何干预。

OK,讲完了这些,让我们来分析一下那两段代码哈。第一段代码我们可以看出是一行一行的遍历数组,我们称之为行优先遍历。而我们知道,在C语言当中,数组是按照行优先的顺序来存储的。那么,这个行优先遍历不就是和数组在存储器中存放的方式一样吗?所以,根据空间局部性的原理,它会把附近的元素给一起取出来,放入缓存中。举个例子,当我访问a[0][0]的时候,就会把a[0][0]后面的a[0][1]、a[0][2]、a[0][3]……放入缓存中。当程序需要a[0][1]的时候,cpu不就可以直接从缓冲区中取到这个数据吗?我们知道,缓存区的读取速度是远远大于内存的。所以第一段代码很好的利用了局部性。这是一个良好的局部性程序(这是步长为1的引用模式)。

现在来看看第二段代码额:-O

它是列优先遍历的。所以说当我访问了a[0][0]之后,虽然把后面的那些a[0][1]、a[0][2]、a[0][3]……放入了缓存中。但是,它下次需要的是a[1][0]呀,这个元素不在缓存中呀!所以,cpu得从内存中去读取a[1][0]。

这样对内存进行读操作,显然会影响读取速度。所以,第二段代码执行那个累加的循环所花的时间就会更久一些。

思考

1、长为1的引用模式是程序中空间局部性常见和重要的来源。一般而言,随着步长的增加,空间局部性下降。

2、我们要先知道我们所用的语言是按行优先还是列优先的顺序来进行存储数组的。在采取一致的遍历方式遍历数组。效果杠杠的!这是一种很重要的优化代码的方法。

happy ending

开始新的孤独的旅行!不甘落后……我期待的一天,需要另一个人陪……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值