如何提高程序效率

一、程序效率

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

二、效率改善的指导原则

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

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

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

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

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

三、时间效率改善的考虑

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

GetLocalHostName(char* name) 
{     
	char funcName[] = "GetLocalHostName";

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

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

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

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

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

四、几个 实例

效率改善的例A

请理解下面的代码
for( int i = 0; i < numPixels;i++ )
{   
	rendering_context->back_buffer->surface->bits[i] = some_value; 
}

做如下修改是否更好
unsigned char *back_surface_bits = rendering_context->back_buffer->surface->bits;
for( int i = 0; i < numPixels;i++ )
{   
	back_surface_bits[i] = some_value;
}

还可以进一步修改
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,它们的函数形式如下
	int functionA(int event)
	int functionB(int event)
	……
	int functionZ(int event)

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

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

这么做是不是更好?

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值