博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
如何优化程序性能
阅读量:5729 次
发布时间:2019-06-18

本文共 2274 字,大约阅读时间需要 7 分钟。

    这篇笔记主要是摘抄了具体的代码示例,从代码中体会如何优化程序的性能,《深入理解计算机系统》已经看了近三分之二了,越看越发现自己懂得太少太少了,正在题图中的绝望之谷徘徊(我自认为是这样),至少比在愚昧山峰左边的山脚徘徊要好很多。

    我们的编译器已经提供了很好的优化机制,但是还有很多细节编译器优化不到,或者说没胆量去优化,因为有一些激进的优化很有可能会违背程序员的初心。

// 第一种void twiddle1(long *xp, long *yp){    *xp += *yp;    *xp += *yp;}// 第二种void twiddle2(long *xp, long *yp){    *xp += 2* *yp;}复制代码

    例如上面的程序,看到第一种写法,我们可能很容易的就想到第二种写法,但是编译器却不会把它变成这种写法。乍看它们没什么区别,我们来分析一下内存引用。第一种需要 3 次内存引用,即读\*xp、读\*yp、写\*xp;而第二种却需要 6 次内存引用,即2 次读\*xp、2 次读\*yp、2 次写\*xp。所以第一种的性能要比第二种好。

    那编译器看到第一种为什么就想不到第二种写法呢?这不是很简单的规则吗?实际上上面的程序存在xp = yp的情况,即两个指针指向同一个内存位置。

// 第一种*xp += *yp; // xp 处存放的值乘以 2*xp += *yp; // xp 处存放的值乘以 2// 第二种*xp += 2* *yp; // xp 处存放的值乘以 3复制代码

    可以看到,当它们都指向同一块内存时,第一种写法会让原来的值增加 4 倍,而第二种写法会让原来的值增加 3 倍,产生了不同的效果,而编译器会当这种情况可能出现,所以编译器并不会帮我们优化第一种代码,这需要程序员自己去维护。

消除循环的低效率

    相信很多人都写过下面类似的代码,貌似没有什么可以优化的,写的挺好。

void lower1(char *s){    long i;    for(i = 0; i < strlen(s); i++){        if(s[i] >= 'A' && s[i] <= 'Z'){            s[i] -= ('A' - 'a');        }    }}复制代码

    仔细看,会发现每次循环都会去调用strlen()函数,而这个函数明显是要拖累性能的,实际上我们只需要计算一次长度就可以了,现在却每次循环都需要去计算一次长度,所以可以将计算移到前面只计算一次的地方。

void lower2(char *s){    long i;    long len = strlen(s);    for(i = 0; i < len; i++){        if(s[i] >= 'A' && s[i] <= 'Z'){            s[i] -= ('A' - 'a');        }    }}复制代码

    编译器虽然会试着去进行代码的移动,但是最终还是没有优化,是因为改变在哪里调用函数或者调用多少次函数的变换,编译器并不能比较可靠的发现一个函数是否有副作用,比如下面的情况。

long f();long func1(){    return f() + f() + f() + f();}long func2(){    return 4*f();}复制代码

    这段代码和开篇提到的代码在形式上很像,可能你会说:它们不会指到同一块内存了呀,编译器这也不去优化吗?考虑一下f()是下面的形式。

long count = 0;long f(){    return count++;}复制代码

    是不是一下就发现问题了,func1()调用 4 次f(),而func2()只调用 1 次f(),它们最终的结果绝不是简单的 4 倍关系。

编写适合条件传送实现的代码

    如果编译器能够产生使用条件数据传送而不是条件控制转移的代码,那么就可以大大的提高程序的性能,关于条件数据传送和条件控制转移在旧文中描述的已经很明确了。比如下面的第一种写法就比第二种要好。

// 第一种void minmax1(long a[], long b[], long n){    long i;    for(i = 0; i < n; i++){        if(a[i] > b[i]){            long t = a[i];            a[i] = b[i];            b[i] = t;        }    }}// 第二种void minmax2(long a[], long b[], long n){    long i;    for(i = 0; i < n; i++){        long min = a[i] < b[i] ? a[i] : b[i];        long max = a[i] < b[i] ? b[i] : a[i];        a[i] = min;        b[i] = max;    }}复制代码

    暂时就写这几个吧,还有个消除不必要的内存引用,因为它的性能问题不能从代码中直接看出来,就不放出来了,工作中尽自己所能写出优雅的代码。

    题图来自于一位不知名网友,侵权还请联系删除。

转载地址:http://lrpwx.baihongyu.com/

你可能感兴趣的文章
利用广播实现ip拨号——示例
查看>>
ProbS CF matlab源代码(二分系统)(原创作品,转载注明出处,谢谢!)
查看>>
OC中KVC的注意点
查看>>
JQ入门(至回调函数)
查看>>
1112: 零起点学算法19——输出特殊值
查看>>
【洛天依】几首歌的翻唱(无伴奏)
查看>>
strcspn
查看>>
OpenSSL初瞻及本系列的博文的缘由
查看>>
ISO8583接口的详细资料
查看>>
tmux不自动加载配置文件.tmux.conf
查看>>
经验分享:JavaScript小技巧
查看>>
[MOSEK] Stupid things when using mosek
查看>>
【云吞铺子之专家来了】CDN的HTTPS相关问题及处理思路
查看>>
程序实例---栈的顺序实现和链式实现
查看>>
服务的使用
查看>>
Oracle 用户与模式
查看>>
网站开发流程以及HTML5简介(八)
查看>>
MairDB 初始数据库与表 (二)
查看>>
RabbitMQ】三种Exchange模式——订阅、路由、通配符模式
查看>>
连接数据库——java
查看>>