对于性能的优化, Jon Bentley告诉我要分5个步骤:
1) 算法和数据结构的选择
2) 算法的优化
3) 数据结构的重组
4) 代码优化
5) 提升硬件性能
我想谈谈关于代码优化的问题.
我们知道java中StringBuffer 和 String的区别, 在处理散列时要用HashMap来代替HashTable, 对于输入/输入流的处理尽量尝试使用Reader/Writer...
一个追求速度的程序员会将优化的代码体现在他的每一段程序上, 以下是几个程序片段:
1) 乘/除法如果使用位运算要比"*" 和 "/" 快一些
result = 4 * 15 的等价代码:
result = 4 << 4 - 1 (15 = 2 * 2 * 2 * 2 - 1)
2) 循环和减法要比直接使用求模运算符获得更好的性能
a % b 的等价代码:
while(a >= b)
a -= b;
3) 对于交换两个数a,b, 位运算比声明中间变量更快
int temp = a;
a = b;
b = temp;
等价代码:
a = a ^ b;
b = b ^ a;
a = a ^ b;
4) 如果代码在连续的内存块中, 将获得更好的性能
if(result != null)
do something useful;
的替代代码:
if(result == null)
;
else
do something useful;
替代代码将有效的逻辑放在了和前置代码相邻的内存块中
如果你不知道这些替代代码, 看完后你也许激动不以, 迅速将它们应用到实践, 但是请稍等, 考虑一个问题, 坐你身边同行们是否认同这些代码? 这些代码是否会降低你程序的可读性及可维护性?
我实现了一个简单的快速排序算法, 代码片段如下:
/* x 中存放N个随机整数*/
private void sort(int l,int r){
if(l > r)
return;
int m = qsort(l,r);
sort(l,m - 1);
sort(m + 1,r);
}
/**
* 以最左元素为比较元素,实现快速排序
*/
private int qsort(int l,int r){
int m = l;
if(l >= r)
return l;
for(i = l + 1; i <=r; i++) {
if(x[i] < x[l]){
swap(++m, i);
}
}
swap(l, m);
return m;
}
private void swap(int a, int b){
x[a] ^= x[b];
x[b] ^= x[a];
x[a] ^= x[b];
}
对10个[0,100]的随机数进行排序, 打印结果如下:
sourceData:
44,97,55,86,94,13,34,89,12,29
quickSort:
0,12,29,34,44,0,0,0,0,97
这些0是从哪里来的? 为什么会得出这种结果?
仔细观察结果发现, 除了0之外, 其它的数都排列正确. 这使我并没有马上检查qsort方法, 而是把原来的swap方法改成了庶民的版本:
int temp = x[a];
x[a] = x[b];
x[b] = temp;
重新编译, 打印结果:
sourceData:
8,69,18,34,29,97,0,64,98,84
quickSort:
0,8,18,29,34,64,69,84,97,98
重新检查swap方法, 发现当两个参数相等时, swap将x[a],x[b]全部置0, 没错, 此时x[a],x[b]本来就指向同一个位置, 在进行第一步x[a] ^= x[b]操作时, x[a]就变成了0, 此后的异或没有半点用处. 当然qsort方法的代码大概是快速排序中最简单的, 同时也是性能最差的, 在极端的情况下它会退化, 有N个改进版本, 让我们看一下第二个版本...哦, 好像偏题了.
我的结论, 比起不起眼的性能提升, 提高程序的可读性和可维护性更加重要. 在web应用中, 速度的瓶颈主要是算法的设计, 数据库的优化, SQL语句的优化, 网络的速度, 机器的性能.