如何提高程序效率

本文探讨了程序效率的概念,提供了改善效率的指导原则,并详细介绍了如何在满足正确性、可靠性、健壮性、可读性的前提下,通过减少执行次数、减少占用空间、优化数据结构和算法、提高循环体效率、减少指针定位和提高数学表达式效率等方法,提高程序的整体效率。同时,文章还通过实例展示了具体的操作方法,旨在帮助开发者在确保程序质量的同时,实现时间和空间资源的最大化利用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、程序效率

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

二、效率改善的指导原则

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

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

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

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

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

三、时间效率改善的考虑

-减少内存分配的次数
一次能够申请的内存,就不要多次申请;
被多次访问函数中存储“不变量”的变量请定义成为static。如:

  1. GetLocalHostName(char* name)   
  2. {       
  3.     char funcName[] = "GetLocalHostName";  
  4.   
  5.         sys_log( "%s begin......", funcName );   
  6.     ...   
  7.     sys_log( "%s end......", funcName );   
  8. }   

如果这是一个经常调用的函数,每次调用时都要对funcName进行分配内存,这个开销很大啊。把这个变量声明成static吧,当函数再次被调用时,就会省去了分配内存的开销,执行效率也很好。 
-提高循环体效率
减少循环次数
减少循环体内执行语句的数量
在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU 跨切循环层的次数
下面例子a和例子b的功能一样,但效率不同
例a:  
  1. for (i=0; i<5;i++)  
  2. {  
  3.     for (j=0; j<100; j++)  
  4.     {  
  5.         Dothing();  
  6.     }  
  7. }  
例b:  
  1. for (j=0; j<100;j++)  
  2. {  
  3.     for (i=0; i<5; i++)  
  4.     {  
  5.         Dothing();  
  6.     }  
  7. }   

-减少指针定位
指针(->)使用很方便,但实际运行往往需要进行地址计算;不必要的地址计算会导致性能的下降;
尽可能减少->的多级嵌套。

-提高数学表达式的效率
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
  1. typedef  struct {  
  2.     short   a;  
  3.     int     b;  
  4.     short   c;  
  5. } AA_t;  
例b
  1. typedef struct  
  2.     short   a;  
  3.     short   c;  
  4.     int     b;  
  5. } BB_t   

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

-动态内存使用的方式,可以提高内存的利用率。
  追求空间的效率和追求时间的效率,往往是矛盾的,需要全面权衡。

-减少代码的行数可以减少ROM的占用
   对于嵌入系统而言,ROM资源是很宝贵的。减少代码行数是减少ROM占用量 的有效途径;
   减少代码行的方法:
消除冗余代码可以有效减少代码行数
通过函数指针和函数表可以减少程序代码规模

四、几个 实例

效率改善的例A

请理解下面的代码
  1. forint i = 0; i < numPixels;i++ )  
  2. {     
  3.     rendering_context->back_buffer->surface->bits[i] = some_value;   
  4. }  

做如下修改是否更好
  1. unsigned char *back_surface_bits = rendering_context->back_buffer->surface->bits;  
  2. forint i = 0; i < numPixels;i++ )  
  3. {     
  4.     back_surface_bits[i] = some_value;  
  5. }  

还可以进一步修改
  1. unsigned char *back_surface_bits = rendering_context->back_buffer->surface->bits;  
  2. forint i = 0; i < numPixels;i++,back_surface_bits++ )  
  3. {     
  4.     *back_surface_bits = some_value;  
  5. }  

效率改善的例B

问题:有一组处理函数:functionA, functionB,… functionZ,它们的函数形式如下
  1. int functionA(int event)  
  2. int functionB(int event)  
  3. ……  
  4. int functionZ(int event)  

他们分别是不同状态(A,B…,Z)的处理。编写这段处理代码,我们该如何做?
下面代码可行吗?
  1. switch (status) {  
  2.     case A:    functionA(event)  
  3.         break;  
  4.     case B:    functionB(event)  
  5.         break;  
  6.     ……  
  7.     case Z:    functionZ(event)   
  8.         break;  
  9. }  

可行!但是不好!原因是生成目标代码大,而且可维护弱一些。
这么做可以解决上面提到的缺点
  1. typdef  int (*pFunc)(int event);  
  2. typedef enum {   A =0,  
  3.     B,  
  4.     …  
  5.     Z  
  6. } Status_t;  
  7.   
  8.   
  9. pFunc  functionlist[Z] ={     
  10.     functionA,  
  11.     functionB,  
  12.     …  
  13.     functionZ  
  14. };   
  15.   
  16.   
  17. Status_t   status;  
  18. ……  
  19. status被赋值  
  20. ……  
  21. functionlist[status](event);    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值