巧用CPU缓存优化代码:数组 vs. 链表(转)
2009-03-30 11:10
363 查看
一个常见的编程问题: 遍历同样大小的数组和链表, 哪个比较快? 如果按照大学教科书上的算法分析方法,你会得出结论,这2者一样快, 因为时间复杂度都是 O(n)。 但是在实践中, 这2者却有极大的差异。 通过下面的分析你会发现, 其实数组比链表要快很多。
首先介绍一个概念:memory hierarchy (存储层次结构),电脑中存在多种不同的存储器,如下表
CPU 寄存器 – immediate access (0-1个CPU时钟周期)
CPU L1 缓存 – fast access (3个CPU时钟周期)
CPU L2 缓存 – slightly slower access (10个CPU时钟周期)
内存 (RAM) – slow access (100个CPU时钟周期)
硬盘 (file system) – very slow (10,000,000个CPU时钟周期)
(数据来自 http://www.answers.com/topic/locality-of-reference)
各级别的存储器速度差异非常大,CPU寄存器速度是内存速度的100倍! 这就是为什么CPU产商发明了CPU缓存。 而这个CPU缓存,就是数组和链表的区别的关键所在。
CPU缓存会把一片连续的内存空间读入, 因为数组结构是连续的内存地址,所以数组全部或者部分元素被连续存在CPU缓存里面, 平均读取每个元素的时间只要3个CPU时钟周期。 而链表的节点是分散在堆空间里面的,这时候CPU缓存帮不上忙,只能是去读取内存,平均读取时间需要100个CPU时钟周期。 这样算下来,数组访问的速度比链表快33倍! (这里只是介绍概念,具体的数字因CPU而异)
因此,程序中尽量使用连续的数据结构,这样可以充分发挥CPU缓存的威力。 这种对缓存友好的算法称为 Cache-oblivious algorithm, 有兴趣可以参考相关资料。再举一个简单例子:
对比
for i in 0..n
for j in 0..m
for k in 0..p
C[i][j] = C[i][j] + A[i][k] * B[k][j];
和
for i in 0..n
for k in 0..p
for j in 0..m
C[i][j] = C[i][j] + A[i][k] * B[k][j];
虽然两者执行结果一样,算法复杂度也一样,但是你会发现第二种写法要快很多。
总结一下, 各种存储器的速度差异很大,在编程中绝对有必要考虑这个因素。 比如,内存速度比硬盘快1万倍,所以程序中应该尽量避免频繁的硬盘读写;CPU缓存比内存快几十倍,在程序中尽量多加利用。
>> 原创文章的版权属于作者,转载请注明出处和作者信息(http://blog.csdn.net/WinGeek/), 谢谢。 <<
首先介绍一个概念:memory hierarchy (存储层次结构),电脑中存在多种不同的存储器,如下表
CPU 寄存器 – immediate access (0-1个CPU时钟周期)
CPU L1 缓存 – fast access (3个CPU时钟周期)
CPU L2 缓存 – slightly slower access (10个CPU时钟周期)
内存 (RAM) – slow access (100个CPU时钟周期)
硬盘 (file system) – very slow (10,000,000个CPU时钟周期)
(数据来自 http://www.answers.com/topic/locality-of-reference)
各级别的存储器速度差异非常大,CPU寄存器速度是内存速度的100倍! 这就是为什么CPU产商发明了CPU缓存。 而这个CPU缓存,就是数组和链表的区别的关键所在。
CPU缓存会把一片连续的内存空间读入, 因为数组结构是连续的内存地址,所以数组全部或者部分元素被连续存在CPU缓存里面, 平均读取每个元素的时间只要3个CPU时钟周期。 而链表的节点是分散在堆空间里面的,这时候CPU缓存帮不上忙,只能是去读取内存,平均读取时间需要100个CPU时钟周期。 这样算下来,数组访问的速度比链表快33倍! (这里只是介绍概念,具体的数字因CPU而异)
因此,程序中尽量使用连续的数据结构,这样可以充分发挥CPU缓存的威力。 这种对缓存友好的算法称为 Cache-oblivious algorithm, 有兴趣可以参考相关资料。再举一个简单例子:
对比
for i in 0..n
for j in 0..m
for k in 0..p
C[i][j] = C[i][j] + A[i][k] * B[k][j];
和
for i in 0..n
for k in 0..p
for j in 0..m
C[i][j] = C[i][j] + A[i][k] * B[k][j];
虽然两者执行结果一样,算法复杂度也一样,但是你会发现第二种写法要快很多。
总结一下, 各种存储器的速度差异很大,在编程中绝对有必要考虑这个因素。 比如,内存速度比硬盘快1万倍,所以程序中应该尽量避免频繁的硬盘读写;CPU缓存比内存快几十倍,在程序中尽量多加利用。
>> 原创文章的版权属于作者,转载请注明出处和作者信息(http://blog.csdn.net/WinGeek/), 谢谢。 <<
相关文章推荐
- [编程技巧] 巧用CPU缓存优化代码:数组 vs. 链表
- 巧用CPU缓存优化代码: 数组VS链表
- [编程技巧] 巧用CPU缓存优化代码:数组 vs. 链表
- [编程技巧] 巧用CPU缓存优化代码:数组 vs. 链表
- 巧用CPU缓存优化代码:数组 vs. 链表(转)
- 巧用CPU缓存优化代码:数组 vs. 链表
- 【转】巧用CPU缓存优化代码:数组 vs. 链表
- 一道简单的acm题的三种解决方案(数组、单向链表、容器vector)与代码优化
- 【转载】利用CPU缓存的特性优化数据存储---数组vs链表
- 【代码优化】返回0长度数组或者集合
- 从缓存友好的角度分析数组和链表
- 数组仿真链表的优化
- C/C++代码被 VS 2010 优化掉了,如何关闭优化?
- 算法学习笔记之四:巧妙运用指针解决链表、字符串、数组等问题(同向双指针VS对向双指针)
- 代码优化:复制数组
- c语言-链表VS数组
- VS项目编译包含CUDA的静态库及在原项目中添加CUDA优化代码方法
- 利用VS的代码优化和openmp并行计算提高程序运行速度
- 从cpu和内存来理解为什么数组比链表查询快
- VS 优化C++代码几点注意事项