(在此反省自己:作为一个计算机系的学生,编程时大多只考虑了程序和算法的正确性,极少考虑程序的性能、运行的时间和空间,可能造成了很多时间和运算资源的浪费。直到今年参加了CCSP竞赛,对于前几道题能够有基本的思路但是写出来提交上去大部分就是超时,才让我深刻地认识到程序优化的重要性,在此阅读学习多篇博文,并将自己学到的Tricks总结如下,希望自己以后能够在这方面多多加强,也与各位博友共勉~)
首先,我们分析性能瓶颈一般是出现在循环处,因此在循环处的程序优化就显得极为关键。下面将给出优化的一些基本方法。
1、提取重复操作
例:
for (i=0; i<len(v); i++) dest = dest OP 2;
每次循环是我们都要计算一次len(v),这对于长度固定不变的数组v来说无疑是一种冗余,我们可以在循环前就定义一个局部变量v_length保存数组的长度,这样就能只计算一次数组长度,减少运行的时间。
2、减少函数调用
函数的调用涉及到栈的调用,入口、返回位置的保存,变量的传递等等,对时间和空间都是一种浪费。
3、减少内存读写
指针直接涉及到内存地址的访问,比直接存储在寄存器中的变量访问要慢得多,因此我们应该将内存访问的操作尽可能地转变成访问寄存器的操作,这样可以节约大量的时间。
4、循环展开
循环展开是指尽量减少循环的次数,有一部分的操作移到每次的循环内部进行。比如将n次的循环变成n/2次,每次循环内部做两个元素的操作。
5、提高并行性
消除前后的数据以来,使得多个运算可以同时开展,进而减少运行时间。
注:循环展开、多路并行并不是越多越好,因为寄存器的个数是有限的,如果局部变量过多就会被放入存储器中,反而严重降低程序的执行效率。
6、减少值传递,多用引用传递参数
在调用函数时,如果值传递传入的是一个类的对象时,就需要重新构造这个对象,是用完之后还需要析构,效率非常低,因此建议多采用引用或指针。
7、++i和i++无影响时,使用++i
当对类使用++操作时,前加是直接改变自己的内部状态,并且直接返回自己的引用,二后加则需要调用复制构造函数,返回时还需要调用析构函数,每次比前加 两次函数,因此在两者没有影响时,应尽量使用前加。
8、避免过大的循环
循环时会在短时间内反复地访问部分变量,因此就会利用到Cache,但是Cache的空间有限,如果循环内部的程序过长的话,Cache就不能够得到充分的运用,其中的内容会不断地变化,反而导致效率的降低。
9、局部变量效率高于静态变量
局部变量是存在于堆栈中的,反复使用的一部分空间就会留在一级缓存(Cache)中,而静态变量则更多的储存在内存中。
10、避免使用多重继承
11、减少除法运算的使用
可以通过数学的方法把除法变为乘法运算;或者将int类型强制转化为unsigned。
12、将短函数声明为内联函数(inline)
13、多用直接初始化
ClassTest ct2(ct1); //直接初始化
ClassTest ct3 = ct1; //复制初始化
这是目前学习总结的一小部分经验,会持续更新的~~~