当前位置: 首页 > news >正文

[编程技巧] 巧用CPU缓存优化代码:数组 vs. 链表

一个常见的编程问题: 遍历同样大小的数组和链表, 哪个比较快? 如果按照大学教科书上的算法分析方法,你会得出结论,这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/), 谢谢。 <<

相关文章:

  • 保存Bitmap到内存流中引发“GDI+中发生一般性错误”
  • Asp.net Mvc使用PagedList分页
  • [Web开发] PSD 转换成HTML/CSS 的工具网站
  • 算法练习--整数拆分为素数乘积
  • 算法练习--卡片游戏
  • [IE编程] 了解Urlmon.dll和Wininet.dll
  • 算法练习--小球下落
  • 在LINQ to SQL中处理“更新已被其它用户删除对象”的错误
  • 算法练习--打印Cantor 数表
  • 企业中的4种人才
  • Sun的启示------技术在企业发展中的分量
  • Computer Science 学习第四章--CPU 指令集及指令处理
  • 领域模型驱动应用心得....
  • 算法练习--除法
  • 移动互联网 3G时代的“新宠”
  • [Vue CLI 3] 配置解析之 css.extract
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • ➹使用webpack配置多页面应用(MPA)
  • CAP理论的例子讲解
  • CentOS7简单部署NFS
  • centos安装java运行环境jdk+tomcat
  • crontab执行失败的多种原因
  • exports和module.exports
  • JavaScript类型识别
  • Java的Interrupt与线程中断
  • Js基础知识(一) - 变量
  • leetcode98. Validate Binary Search Tree
  • leetcode讲解--894. All Possible Full Binary Trees
  • Next.js之基础概念(二)
  • Python连接Oracle
  • Vue2.0 实现互斥
  • windows-nginx-https-本地配置
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 观察者模式实现非直接耦合
  • 理清楚Vue的结构
  • 前端临床手札——文件上传
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 新书推荐|Windows黑客编程技术详解
  • 学习HTTP相关知识笔记
  • 译自由幺半群
  • 正则表达式
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • ​什么是bug?bug的源头在哪里?
  • #vue3 实现前端下载excel文件模板功能
  • #在 README.md 中生成项目目录结构
  • (AngularJS)Angular 控制器之间通信初探
  • (办公)springboot配置aop处理请求.
  • (第61天)多租户架构(CDB/PDB)
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (三十五)大数据实战——Superset可视化平台搭建
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置