性能在软件工程诞生时就占据着非常重要的位置 , 如何用更少的硬件资源来支撑更多的功能、来完成更多的任务是软件工程师的职责 , 也是用来衡量一个软件工程师技艺高低的标准 。这跟炒菜是一个道理 , 同样的食材 , 在饭店的师傅手里跟普通人手里的做法是有很大的差别的;食堂师傅是工程化的做法 , 讲究是短时间炒制更多的菜 , 而且味道不能掉;而普通人则比较随意 , 没有什么章法 , 而且可能只是爱好或者放松的渠道 , 所以不用考虑炮制的性能如何 , 能不能达到预计的目标 。简单来说 , 厨师是靠手艺去赚钱 , 而其他人只是玩玩 。那么程序员的手艺体现在哪呢?可以肯定的说 , 性能调优是最重要的一环 , 也是最基本的一环 , 甚至我觉得只有掌握这个技能后才能够进阶做构架或者做设计 , 否则如果反其道而行之则会举步维艰 。
这时你可能会说 , 我是觉得性能是很重要 , 但是怎么去学呢?IT是个发展迅速的行业 , 每年涌现的新技术 , 新框架数不胜数 , 多如繁星 , 往往还没学懂JAVA , Go都快被淘汰了……一茬接一茬 , 无从下手 。如果你常常有这个感觉 , 那么这篇文章可能对你有帮助 。
性能优化的套路先说结论 , 性能优化或者说如何能够开发出效率更高的程序来(当然硬件资源一样且使用率一样的条件下) , 只有两条路:
1. 掌握局部性原理
2. 掌握基本的算法设计与分析
在现有计算机构架下(冯诺依曼构架)这是调优的充分必要条件 , 换句话说就是 , 如果你写了一个性能比别人好的程序 , 那么只有两种情况 , 要么是局部性原理用得更好 , 要么是就是采用了更好的算法;同时 , 如果你想要写出比别人好的程序 , 那么你也只有两条路可以走 , 运用更底层的局部性优化设计 , 或者设计更好的算法来解决这个问题 。
局部性原理如果你在软件工程领域“阅历”足够丰富 , 你就会有恍然大悟的感觉 , 因为这种例子实在太多:linux中的硬盘缓冲、页缓存 , redis中元素较少的时候用ziplist代替hashmap可能还会带来性能的提升 , 内存的减少;Kafka依赖的磁盘缓存 , 分区存储机制 , MySQL的B+树索引;更底层的CPU的Cacheline技术 , 分页技术等等其实都是用了局部性原理来作为理论基础的 。那么什么是局部性原理呢?
简单来说分为三个要点:
- 程序总是按照“批”来处理数据 , 这样效率最高;比如:CPU读取内存是按照批来处理如:一个cacheline=64/128byte,内存与硬盘按照4KB来读取 。因为计算机结构的特点 , 各级设备(CPU到内存到硬盘与外设)之间的访问速度是有数量级的差别;所以就注定不能一个个字节来读取;这个现象决定计算机优化的方向 , 被称为冯诺依曼瓶颈;
- 最近访问过的资源(内存位置) , 可能近期内还会被访问 , 这个叫做时间局部性 , 对应的解决方案是缓存;
- 当前位置内存被访问过 , 那么大概率旁边的内存也会被后续访问 , 这个叫做空间局部性 , 对应的解决方案是预加载;
还是拿做饭这件事举例子 。当我们去买菜的时候 , 会尽可能的减少去菜市场的时间 , 也肯定不可能发现什么菜没有了再临时去菜市场购买 , 这样“IO”就太重了 , 要使用局部性原理来解决 。就炒菜的例子来说 , 我们要炒青椒炒肉这个菜;首先是买菜 , 我们发现在买青椒的时候可以把葱姜蒜也都一并买了 , 因为蔬菜区往往是相邻的;而买肉的时候 , 尽量也把酱油醋都一并买了 , 它们也是很可能也是挨着的;这种在空间上相邻的提前加载这就是“预加载”了;而回到家 , 我们开始炒菜的时候 , 厨房的布置往往是炒菜的锅子跟油盐酱醋是分开放置的 , 但是炒菜的时候要经常加盐、放酱油 , 所以为了减少来回取油盐的时间 , 会在炒菜的时候将配菜与油盐放置在炒锅的附近 , 加快炒菜的速度 , 等炒完后又重新放回去 , 这个就叫做“缓存”的思维——把经常使用的资源放在工作较近的地方 , 等使用完再释放 。
推荐阅读
- 软件测试需要学什么?
- 据说让你抓狂的Nginx性能调优,我却这么轻松就搞定了
- 要精通SQL优化?首先要看懂explain关键字
- CENTOS自动巡检服务器性能指标
- 如何60秒内分析Linux性能
- 电脑杀毒软件有哪些
- Win10优化技巧,性能提升10%以上
- 如何写好网站关键词优化方案
- 一加|2499元!一加Ace上手:性能一绝 无明显短板
- javascript 代码的简单优化