C语言编程之局部性

什么是局部性

一个编写良好的计算机程序常常具有良好的局部性(locality)。即,他们倾向于引用临近与其最近引用过的数据项的数据项,或者最近引用过的数据项本身。这种倾向性,被称为局部性原理

局部性通常有两种不同的形式:

  • 时间局部性

具有良好时间局部性的程序中,被引用过一次的内存位置很可能在不远的将来再被多次引用。

  • 空间局部性

具有良好空间局部性的程序中,如果一个内存位置被引用了一次,那么程序很可能在不远的将来引用附近的一个内存位置。

局部性原理的应用

一般来说,有良好局部性的程序比局部性差的程序运行得更快。

现代计算机系统的各个层次,从硬件到操作系统、再到应用程序,它们的设计都利用了局部性。

  • 硬件层

局部性原理允许计算机设计者通过引入称为高速缓存存储器,来保存最近被引用得指令和数据项,从而提高对主存的访问速度。

  • 操作系统层

局部性原理允许系统使用主存来缓存磁盘文件系统中最近被使用的磁盘块。

  • 应用程序

局部性原理在应用程序的设计中也扮演着重要角色。例如,Web浏览器将最近被引用的文档放在本地磁盘上。

对程序数据引用的局部性

通过举例来说明程序的局部性

int sumvec(int v[N])
{
	int i, sum = 0;
	
	for(i = 0; i < N; i++)
	{
		sum += v[i];
	}
	return sum;
}

在这段程序代码中,变量 sum 在每次循环迭代中被引用一次,对于 sum 来说,有好的时间局部性。另外,sum 为标量,没有空间局部性。

向量 v 的元素是被顺序读取的,按照它们存储在内存中的顺序一个接一个。对于变量 v ,函数具有很好的空间局部性,但是时间局部性很差。因为每个向量元素只被访问一次。

对于循环体来说,其中的每个变量,要么有好的空间局部性,要么有好的时间局部性。由此断定函数 sumvec 有良好的局部性。

顺序访问一个向量每个元素的函数,具有步长为 1 的引用模式。每隔 k 个元素访问一个连续向量,就称为步长为 k 的引用模式。一般来说,随着步长的增加,空间局部性下降。

多维数组访问举例,二维数组求和,双重嵌套按照行优先顺序:

int sumarrayrows(int a[M][N])
{
	int i, j, sum = 0;
	
	for(i = 0; i < M; i++)
	{
		for(j = 0; j < N; j++)
		{
			sum += a[i][j];
		}
	}
	return sum;
}

这个函数按照数组被存储的***行优先顺序***来访问这个数组,是一个以步长为 1 的引用模式,具有良好的空间局部性。

如果是以***列优先顺序***进行访问这个数组,for 循环修改为

for(j = 0; j < N; j++)
{
  for(i = 0; i < M; i++)
  {
	  sum += a[i][j];
  }
}

这个循环是按照***列优先顺序***扫描数组,而C语言的数组在内存中是按照 行顺序 来存放的。结果得到步长为 N 的引用模式,导致这个循环的空间局部性很差。

取指令的局部性

程序的指令是存放在内存中的,CPU 必须取出这些指令,因此也可以评价一个程序关于取指令的局部性。

for 循环体里的指令是按照连续的内存顺序执行的,因此循环具有良好的空间局部性。

循环体会被执行多次,因此,它也有很好的时间局部性。

小结

量化评价程序中局部性的一些简单原则为:

  • 重复引用相同变量的程序有良好的时间局部性
  • 对于具有步长为 k 的引用模式的程序,步长越小,空间局部性越好。具有步长为 1 的引用模式的程序,具有很好的空间局部性。在内存中以大步长跳来跳去的程序,空间局部性会很差。
  • 对于取指令来说,循环有好的时间和空间局部性。循环体越小,循环迭代次数越多,局部性越好。

参考资料:《深入理解计算机系统》


关注公众号【一起学习嵌入式】,获取更多精彩内容

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
目 录 第1章 C语言 8 1.1 什么是局部程序块(local block)? 8 1.2 可以把变量保存在局部程序块中吗? 9 1.3 什么时候用一条switch语句比用多条if语句更好? 9 1.4 switch语句必须包含default分支吗? 10 1.5 switch语句的最后一个分支可以不要break语句吗? 11 1.6 除了在for语句中之外,在哪些情况下还要使用逗号运算符? 11 1.7 怎样才能知道循环是否提前结束了? 13 1.8 goto,longjmp()和setjmp()之间有什么区别? 13 1.9 什么是左值(lvaule)? 15 1.10 数组(array)可以是左值吗? 15 1.11 什么是右值(rvaule)? 16 1.12 运算符的优先级总能保证是“自左至右”或“自右至左”的顺序吗? 17 1.13 ++var和var++有什么区别? 17 1.14 取模运算符(modulus operator)“%”的作用是什么? 17 第2章 变量和数据存储 18 2.1. 变量存储在内存(memory)中的什么地方? 18 2.2. 变量必须初始化吗? 19 2.3. 什么是页抖动(pagethrashing)? 19 2.4. 什么是const指针? 20 2.5. 什么时候应该使用register修饰符?它真的有用吗? 21 2.6. 什么时候应该使用volatile修饰符? 21 2.7. 一个变量可以同时被说明为const和volatile吗? 22 2.8. 什么时候应该使用const修饰符? 23 2.9. 浮点数比较(floating-point comparisons)的可靠性如何? 23 2.10. 怎样判断一个数字型变量可以容纳的最大值? 24 2.11. 对不同类型的变量进行算术运算会有问题吗? 25 2.12. 什么是运算符升级(operatorpromotion)? 25 2.13. 什么时候应该使用类型强制转换(typecast)? 26 2.14. 什么时候不应该使用类型强制转换(typecast)? 27 2.15. 可以在头文件中说明或定义变量吗? 27 2.16. 说明一个变量和定义一个变量有什么区别? 27 2.17. 可以在头文件中说明static变量吗? 28 2.18. 用const说明常量有什么好处? 28 第3章 排序与查找 28 排序 28 查找 29 排序或查找性能? 30 3.1. 哪一种排序方法最方便? 32 3.2. 哪一种排序方法最快? 33 3.3. 对外存(磁盘或磁带)中而不是内存中的数据进行排序称为外部排序。 39 3.4. 1哪一种查找方法最方便? 44 3.5. 1哪一种查找方法最快? 46 3.6. 1什么是哈希查找? 51 3.7. 1怎样对链表进行排序? 53 3.8. 1怎样查找链表中的数据? 53 第4章 数据文件 59 4.1. 当errno为一个非零值时,是否有错误发生? 59 4.2. 什么是流(stream)? 59 4.3. 怎样重定向一个标准流? 60 4.4. 怎样恢复一个重定向了的标准流? 60 4.5. stdout能被强制打印到非屏幕设备上吗? 61 4.6. 文本模式(textmode)和二进制模式(binarymode)有什么区别? 61 4.7. 怎样判断是使用流函数还是使用低级函数? 62 4.8. 怎样列出某个目录下的文件? 62 4.9. 怎样列出一个文件的日期和时间? 63 4.10. 怎样对某个目录下的文件名进行排序? 66 4.11. 怎样判断一个文件的属性? 67 4.12. 怎样查看PATH环境变量? 69 4.13. 怎样打开一个同时能被其它程序修改的文件? 69 4.14. 怎样确保只有你的程序能存取一个文件? 71 4.15. 怎样防止其它程序修改你正在修改的那部分文件内容? 71 4.16. 怎样一次打开20个以上的文件? 72 4.17. 怎样避开"Abort,Retry,Fail”消息? 72 4.18. 怎样读写以逗号分界的本? 74 第5章 编译预处理 76 5.1. 什么是宏(macro)?怎样使用宏? 76 5.2. 预处理程序(preprocessor)有什么作用? 77 5.3. 怎样避免多次包含同一个头文件? 79 5.4. 可以用#include指令包含类型名不是".h"的文件吗? 80 5.5. 用#define指令说明常量有什么好处? 80 5.6. 用enum关键字说明常量有什么好处? 81 5.7. 与用#define指令说明常量相比,用enum关键字说明常量有什么好处? 81 5.8. 如何使部分程序在

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zsky_01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值