您的位置:首页 > 其它

如何提高程序效率

2015-07-13 16:23 183 查看
一、程序效率

程序效率,是用执行的步骤(step)数――时间复杂度、占内存的多少来衡量的――空间复杂度。完成某项工作,执行的步骤(step)的次数最少、
占用内存最小是程序员所追求的。特别是嵌入式系统的开发,内存等资源都是有限的。

因此,提高效率的着眼点应该是

减少执行次数

减少占用空间

二、效率改善的指导原则

-满足正确性、可靠性、健壮性、可读性等质量因素的前提下,设法提高程序的效率;
如果程序的正确性、可靠性得不到保证,提高效率就失去了根本;
如果程序的健壮性得不到保证,提高效率就失去了目标;
如果程序的可读性得不到保证,提高效率就失去了方向;

-以提高程序的全局效率为主,提高局部效率为辅;
如何只从局部角度出发,局部效率的改善一般对全局效率改善作用不大,有时甚至影响全局效率的改善;
应该从全局角度出发,整体考虑,作出统一改善的调整,有的时候局部利益为配合整体需要应作出牺牲;

-在优化程序的效率时,应当先找出限制效率的“瓶颈”;
非关键点的改善,不会根本改变效率的现状;
先进行一些基准数据测量和问题收集,寻找提高效率的关键点;
有时一次关键的改动还不能解决问题,还需要进一步的数据测量和持续的改进,直到符合要求;

-先优化数据结构和算法,再优化执行代码;
因为O(n2)的算法写不出O(nlog2n)的程序,因此写程序前应该考虑数据结构和算法的选择和优化;
如果你已经选择了正确的算法,那么只有到了写程序的最后,才有可能去关心执行代码的优化问题;

-时间效率和空间效率可能对立,此时应当分析那个更重要,作出适当的折衷;
一般来讲,在空间允许的时候,我们会花费空间换取时间效率的大幅提升;
当空间受限--时间效率和空间对立的时候,我们根据需要,在两者之间作出适当折中;

三、时间效率改善的考虑

-减少内存分配的次数

一次能够申请的内存,就不要多次申请;

被多次访问函数中存储“不变量”的变量请定义成为static。如:

[cpp] view
plaincopy

GetLocalHostName(char* name)   

{       

    char funcName[] = "GetLocalHostName";  

  

        sys_log( "%s begin......", funcName );   

    ...   

    sys_log( "%s end......", funcName );   

}   

如果这是一个经常调用的函数,每次调用时都要对funcName进行分配内存,这个开销很大啊。把这个变量声明成static吧,当函数再次被调用时,就会省去了分配内存的开销,执行效率也很好。 

-提高循环体效率

减少循环次数

减少循环体内执行语句的数量
在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU 跨切循环层的次数

下面例子a和例子b的功能一样,但效率不同

例a:   

[cpp] view
plaincopy

for (i=0; i<5;i++)  

{  

    for (j=0; j<100; j++)  

    {  

        Dothing();  

    }  

}  

例b:   

[cpp] view
plaincopy

for (j=0; j<100;j++)  

{  

    for (i=0; i<5; i++)  

    {  

        Dothing();  

    }  

}   

-减少指针定位

指针(->)使用很方便,但实际运行往往需要进行地址计算;不必要的地址计算会导致性能的下降;

尽可能减少->的多级嵌套。

-提高数学表达式的效率

a*b + a*c = a*(b+c); 减少一次乘法,但不改变表达式的意义。

b/a + c/a = (1/a)*(b+c); 把两次除法变成一次除法和一次乘法,在几乎所有的平台上,除法都比乘法慢。

(a || b ) && c ) = c && ( a || b ); 当c为假时,第一个表达式要计算( a || b ),第二个表达式则不计算。

四、空间效率改善的考虑

合理结构体成员定义顺序:按照类型从小到大,相同类型连续存放

例a和例b的占用的空间是不同的:

例a

[cpp] view
plaincopy

typedef  struct {  

    short   a;  

    int     b;  

    short   c;  

} AA_t;  

例b

[cpp] view
plaincopy

typedef struct  

    short   a;  

    short   c;  

    int     b;  

} BB_t   

-冗余数据压缩,可以减少对内存的占用

  如有些矩阵数据的存储。有些矩阵中的非零元素很少,可以考虑通过只存储非零数据来减少对存储空间的占用。

-动态内存使用的方式,可以提高内存的利用率。

  追求空间的效率和追求时间的效率,往往是矛盾的,需要全面权衡。

-减少代码的行数可以减少ROM的占用

   对于嵌入系统而言,ROM资源是很宝贵的。减少代码行数是减少ROM占用量 的有效途径;

   减少代码行的方法:
消除冗余代码可以有效减少代码行数
通过函数指针和函数表可以减少程序代码规模

四、几个实例

效率改善的例A

请理解下面的代码

[cpp] view
plaincopy

for( int i = 0; i < numPixels;i++ )  

{     

    rendering_context->back_buffer->surface->bits[i] = some_value;   

}  

做如下修改是否更好

[cpp] view
plaincopy

unsigned char *back_surface_bits = rendering_context->back_buffer->surface->bits;  

for( int i = 0; i < numPixels;i++ )  

{     

    back_surface_bits[i] = some_value;  

}  

还可以进一步修改

[cpp] view
plaincopy

unsigned char *back_surface_bits = rendering_context->back_buffer->surface->bits;  

for( int i = 0; i < numPixels;i++,back_surface_bits++ )  

{     

    *back_surface_bits = some_value;  

}  

效率改善的例B

问题:有一组处理函数:functionA, functionB,… functionZ,它们的函数形式如下

[cpp] view
plaincopy

int functionA(int event)  

int functionB(int event)  

……  

int functionZ(int event)  

他们分别是不同状态(A,B…,Z)的处理。编写这段处理代码,我们该如何做?

下面代码可行吗?

[cpp] view
plaincopy

switch (status) {  

    case A:    functionA(event)  

        break;  

    case B:    functionB(event)  

        break;  

    ……  

    case Z:    functionZ(event)   

        break;  

}  

可行!但是不好!原因是生成目标代码大,而且可维护弱一些。

这么做可以解决上面提到的缺点

[cpp] view
plaincopy

typdef  int (*pFunc)(int event);  

typedef enum {   A =0,  

    B,  

    …  

    Z  

} Status_t;  

  

  

pFunc  functionlist[Z] ={     

    functionA,  

    functionB,  

    …  

    functionZ  

};   

  

  

Status_t   status;  

……  

status被赋值  

……  

functionlist[status](event);      

这么做是不是更好?

版权声明:本文为博主原创文章,未经博主允许不得转载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  优化