年薪80W的架构师总结:性能优化其实不难,记住这十条策略就够了( 三 )


现代的语言往往对异步操作有比较好的支持 , 使得异步编程变得更加简单 , 可读性也更好 。
四、缓存 / 批量合并“缓存 / 批量合并”是优化策略中的第四大类 。缓存和批量合并这两个策略 , 有些场景下会同时起作用 , 所以我把它们放在一起 。
7. 缓存数据
缓存的本质是加速访问 。这是一个用得非常普遍的策略 , 几乎体现在计算机系统里面每一个模块和领域 , CPU、内存、文件系统、存储系统、内容分布、数据库等等 , 都会遵循这样的策略 。
我们最熟悉的应该就是 CPU 的各级缓存了 。在文件系统、存储系统和数据库系统里面 , 也有快速缓存来存储经常访问的数据 , 目的是尽量提高缓存命中率 , 从而避免访问比较慢的存储介质 。
对于一个基于 Web 的应用服务 , 前端会有浏览器缓存 , 有 CDN 存放在边缘服务器上 , 有反向代理提供的静态内容缓存;后端则还会有服务器本地缓存 。
程序设计中 , 对于可能重复创建和销毁 , 且创建销毁代价很大的对象(比如套接字和线程) , 也可以缓存 , 对应的缓存形式 , 就是连接池和线程池等 。
对于消耗较大的计算 , 也可以将计算结果缓存起来 , 下次可以直接读取结果 。比如对递归代码的一个有效优化手段 , 就是缓存中间结果 。
8. 批量合并处理
在有 IO(比如网络 IO 和磁盘 IO)的时候 , 合并操作和批量操作往往能提升吞吐量 , 提高性能 。
我们最常见的是批量 IO 读写 。就是在有多次 IO 的时候 , 可以把它们合并成一次读写数据 。这样可以减少读写时间和协议负担 。比如 , GFS 写文件的时候 , 尽量批量写 , 以减少IO 开销 。
对数据库的读写操作 , 也可以尽量合并 。比如 , 对键值数据库的查询 , 最好一次查询多个键 , 而不要分成多次 。
涉及到网络请求的时候 , 网络传输的时间可能远大于请求的处理时间 , 因此合并网络请求也很有必要 。上层协议呢 , 端到端对话次数尽量不要太频繁(Chatty) , 否则的话 , 总的应用层吞吐量不会很高 。
五、更先进算法和数据结构优化策略中的最后一个大类就是“更先进算法和数据结构” 。这两个策略是紧密配合的 , 比如先进的算法有时候会需要先进的数据结构;而且它们往往和程序的设计代码直接相关 , 所以放在一起 。
9. 先进的算法
同一个问题 , 肯定会有不同的算法实现 , 进而就会有不同的性能 。比如各种排序算法 , 就是各有千秋 。有的实现可能是时间换空间 , 有的实现可能是空间换时间 , 那么就需要根据你自己的实际情况做权衡 。
对每一种具体的场景(包括输入集合大小、时间空间的要求、数据的大小分布等) , 总会有一种算法是最适合的 。我们需要考虑实际情况 , 来选择这一最优的算法 。
10. 高效的数据结构
和算法的情况类似 , 不同的数据结构的特性 , 也是千差万别 。
没有一个数据结构是在所有情况下都是最好的 , 比如你可能经常用到的 Java 里面列表的各种实现 , 包括各种口味的 List、Vector、LinkedList , 它们孰优孰劣 , 取决于很多个指标:添加元素、删除元素、查询元素、遍历耗时等等 。我们同样要权衡取舍 , 找出实际场合下最适合的高效的数据结构 。
六、总结各种性能问题的解决 , 需要采用一些策略;而且不同的人和不同的场景中 , 会采用有时相同有时迥异的策略 , 恰如韩愈所说的“草树知春不久归 , 百般红紫斗芳菲” 。但花草树木争奇斗艳 , 说到底是因为“知春不久归” 。

年薪80W的架构师总结:性能优化其实不难,记住这十条策略就够了

文章插图
 
同样的道理 , 这些性能优化策略 , 有时候很容易想到 , 有时候并不是那么直观 。所以 , 我们需要系统地有层次地思考 , 而这一讲就是帮助你建立这样的思路 。
通过总结十大策略 , 希望你可以多从不同角度 , 思考同一个问题;有时候一个问题看似无解 , 但多方位思考 , 可能会突然发现非常好的解决方案 。


推荐阅读