如何提高程序效率

news/2024/7/10 5:16:15 标签: 数据结构, 优化, 算法, 存储, 嵌入式, 工作
一、程序效率

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

二、效率改善的指导原则

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

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

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

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

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

三、时间效率改善的考虑

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

[cpp] view plain copy
  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:  
[cpp] view plain copy
  1. for (i=0; i<5;i++)  
  2. {  
  3.     for (j=0; j<100; j++)  
  4.     {  
  5.         Dothing();  
  6.     }  
  7. }  
例b:  
[cpp] view plain copy
  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
[cpp] view plain copy
  1. typedef  struct {  
  2.     short   a;  
  3.     int     b;  
  4.     short   c;  
  5. } AA_t;  
例b
[cpp] view plain copy
  1. typedef struct  
  2.     short   a;  
  3.     short   c;  
  4.     int     b;  
  5. } BB_t   

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

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

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

四、几个 实例

效率改善的例A

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

做如下修改是否更好
[cpp] view plain copy
  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. }  

还可以进一步修改
[cpp] view plain copy
  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,它们的函数形式如下
[cpp] view plain copy
  1. int functionA(int event)  
  2. int functionB(int event)  
  3. ……  
  4. int functionZ(int event)  

他们分别是不同状态(A,B…,Z)的处理。编写这段处理代码,我们该如何做?
下面代码可行吗?
[cpp] view plain copy
  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. }  

可行!但是不好!原因是生成目标代码大,而且可维护弱一些。
这么做可以解决上面提到的缺点
[cpp] view plain copy
  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);    


http://www.niftyadmin.cn/n/847698.html

相关文章

编码与解码

编码发展历史&#xff1a;1、汉字的编码的发展&#xff1a;早期计算机使用7位的ASCII编码&#xff0c;为了处理汉字&#xff0c;设计了用于简体中文的GB2312和用于繁体中文的big5。GB2312支持的汉字太少&#xff0c;于是扩增为GBK。GB18030是进一步扩增的版本。在这些版本中&am…

马哥笔记第十七天openssl、CA、scp、sftp、ssh

1、加密算法和协议类型&#xff1a; 对称加密&#xff1a;任意加密数据块和流的内容&#xff0c;加密和解密用同一个密码。 通常明文&#xff08;clear text&#xff09;通过算法和密钥生成密文&#xff0c;再由接受者用相同的密钥和算法解密获取…

关于ARM的C语言优化

0推荐C数据类型1. C语言的程序优化与编译器和硬件系统都有关系&#xff0c;设置某些编译器选项是最直接最简单的优化方式。在默认的情况下&#xff0c;armcc是全部优化功能有效的&#xff0c;而GNU编译器的默认状态下优化都是关闭的。ARM C编译器中定义的char类型是8位无符号的…

vue初探--编写表格组件

在项目当中&#xff0c;经常会有表格组件&#xff0c;包含2部分&#xff0c;其一为table-header,其二为table-content 然后在这个小demo里面涉及到了vue的个别指令: v-for v-model v-bind等。还有父组件和子组建的数据共享&#xff0c;过滤器等功能。 HTML模板:<div id"…

delphi 基础原理--什么是事件/自定义事件

为什么80%的码农都做不了架构师&#xff1f;>>> Events are special properties linked to code that get executed whenever a particular action occurs. This article discusses how events are generated and how you can define your own event properties fo…

sp_executesql接收返回多个参数实例

2019独角兽企业重金招聘Python工程师标准>>> 近日做项目中需要在EXEC执行Sql字符串时动态的传入参数并接收返回值&#xff0c;于是研究了一下SqlServer中sp_executesql的使用方法&#xff0c;并做了如下的例子。在使用sp_executesql动态传入与接收返回参数时需注意以…

U-Boot烧写系统到Nand Flash

1 开发环境 宿主机&#xff1a;Ubuntu14.04.2&#xff08;32bit&#xff09; 开发板&#xff1a;Mini2440 系统&#xff1a;Linux 2 Nand Flash分区表 为了使得系统能正常启动&#xff0c;需要将内核与根文件系统烧写到指定的位置&#xff08;由Nand Flash的分区表指定&#x…

C语言编程优化运行速度

1、选择合适的算法和数据结构 选择一种合适的数据结构很重要&#xff0c;如果在一堆随机存放的数中使用了大量的插入和删除指令&#xff0c;那使用链表要快得多。数组与指针语句具有十分密切的关系&#xff0c;一般来说&#xff0c;指针比较灵活简洁&#xff0c;而数组则比较直…