我对软件优化的一些想法
目前所做的项目,今年应该是第5个release了, 走过了这5年的风风雨雨,中间几度更易开发人员,现在的团队与5年前的团队已是两个完全没有"交集"的团队, 这样必然导致我们对项目会存在很多的不理解,不理解其初衷,不理解其原始设计,不理解其代码。。。对一些不理解的地方不敢大动手脚,只能修修补补以完成需要的功能,其结局从开发角度看就是总体设计的缺失, 代码结构的混乱,从功能角度看就是容易出错,运行速度极慢。
项目极其需要一次深入的代码重构与性能提升,而这都至少需要一个release的时间来做,对于代码重构, 从商业的角度来讲,是十分不可取的,一是其风险比较大,大刀阔斧的重构,如何保证软件的原有功能是个大问题; 而整整一个release的时间做重构,对于用户来讲,他拿到新的版本时,看不到任何新功能与提高,难道你告诉他,我们的代码结构现在很elegent。。。;但对于性能提升,现在是到了不得不做的地步,因为能够大幅度的提升性能,想必用户也能接受一个没有新功能的新版本。
于是, 我们决定用一个release的时间来做性能优化。
当然,我们不打算从学术的角度来考虑, 这个是O(n) 的算法,那个是O(nlgn) 的。。。; 也不打算从语言的角度来看待, 传引用要比传值快,类成员在初始化列表初始化。。。;当然, 并不是说这些不重要, 只是这些都应该是比较常见的,大家都应该清楚的事情, 也就是说我们假设我们的项目中不存在这种问题; 另外就是从语言角度来做的优化, 对我们的性能提升帮助不会太大。 我们会从一个宏观的,特定于我们项目workflow方面的角度来做优化。 主要包括以下几个方面:
一、集中处理 (batch processing)
把相关的操作集中起来处理, 从程序原理上来讲, 集中做相同的操作, 由于数据局部性的原理, 很多数据可以直接从cache中取得, 速度会比较快。 但我们主要考虑的还是另外一个因素,减少不必要的重复的初始化,假设将我有十个对象要update, 一般情况下, 为了做update, 我们必然要准备某些前提数据, 如果十个对象分别处理, 我就要初始化十次, 但如果我先把这十个对象收集起来,到最后一起处理, 最后只会初始化一次前提数据。 这对于update对象密集的情况十分有用。 当然, 这样我们也能有效的减少函数调用次数, 对性能提高也有不少的帮助。
二、减少重复操作(初始化) (reduce repeated operations)
重复操作, 一个是在有循环的时候, 我应该尽量把一些common的操作, 如一些输入数据的初始化提到循环外面来做,这在上面一点中也提到过。 二是对于一些全局的属性,操作等, 我们应该放在内存里,并提供一个全局访问点来直接得到, 而不是每次在需要的时候都去重新初始化一遍。 举个例子来讲, 每个application应该都有他自己的一些configuration, setting, 如果每次我需要这些信息的时候, 都从文件,或者注册表去读一次, 那就非常的浪费时间了, 尤其是涉及到I/O操作的时候。 当然, 这个有点像 cache的概念, 但是还远远不及。
三、消除冗余操作 (avoid redundant operations)
也许你不相信, 一个项目经过很多不同的人的开发, 由于理解上的误差,以及时间紧迫仓促完工,很多workflow上可能会都重复的操作, 仔细检察, 从全局上来考虑整个流程,你会发现, 其实我们做了很多不该做的事。
四、cache机制 (cache mechanism)
Cache的原理是用空间换时间, 当然,这个空间是指内存。我们把一些重要的中间信息放在内存中,以极大的提高查找,更新的速度。一般常用的数据结构就是map, 比如一个对象有长度这么一个属性, 但每次去得这个长度的时候都需要经过复杂的耗时的计算, 如果我们有些操作需要大量的使用到这个对象及其属性, 我们就可以建这样一个map: map<对象指针,长度>, 这样每次用到时, 我只要到这个map中去查就可以了, 如果某个对象被更新了,我们需要更新这个map, 也就是说维护cache.
五、延迟更新 (defer update)
这是一个讲究策略的做法, 比如说我们的项目要在9.1号前demo给客户, 我们要写好代码,并维护好文档, 但是时间很急, 如果我们在9.1号前把这两件时都要做好,恐怕要疯狂加班了, 但是我们知道,客户只需要看到我们软件运行的效果, 文档他暂时并不关心, 那好吧, 我们9.1前就写代码, 文档就在demo后写好了。当然举这个例子的并不是鼓励大家先写代码,后补文档, 而是为了说明有些事情, 如果资源紧张, 我们可以把他分开看待,对于要的不急的那部分, 我们可以先不做, 等到时不忙了, 需要了的时候再做, 以缓解当前的紧张。 从代码角度举个例子, 假设我们有十条样条曲线需要更新, 更新可能包括样条线的方程,图形显示, 以及其长度等等, 如果我这些事情我一下子全做了, 用户可能要等很久, 但是我们知道, 用户做了这个操作, 他只需要看到图形上更新就可以了, 至于长度等什么的, 等他需要了, 或者空闲的时候,我们再给他更新, 这就让整个操作比较流畅了。
这是我通过这个release对软件优化的一些想法,我相信现实中优化的方法是多种多样的,我希望这篇文章能够起到抛砖引玉的作用,希望大家能够提出自己的一些经验来共同分享。