目前位置: VCer资源中心 >>> VCer文章 >>> 软件工程

[本帖已阅读3376次 分值130 回复2次] 张贴资源 发回信箱 控制面板

白乔原创:艺术编程之C++篇[5]

提供者:bluejoe 张贴时间:2004-04-10 12:26:15.0 出处:vcer.net 作者:不祥

白乔原创:艺术编程之C++篇[5](2004-04-10 12:26:15.0)


白乔


 
级别: VCer师长
头衔: VCer创始人

经验: 21093
作品: 513
分会: 华北分会
注册: 2003-12-01 09:20:32.0
登录: 2008-11-17 19:35:24.0

4 编写快的代码——代码的效率性

程序的效率包括时间和空间上的效率,程序运行速度快,或者占用内存小,那么它的效率就高。

在640K内存时代,空间效率是很讲究的;但时过境迁,现在的内存动辄256M,必要的时候Windows还要动用虚拟内存,将上G的硬盘当着内存使,这样一来,空间效率就没有时间效率显得重要了。

所以,以下的内容只讨论程序的时间效率。

4.1 换机器还是改代码?

让程序跑得更快,要么改代码,要么换机器。程序员以固执著称,肯定选择后者;应用商有的是钱,升级打补丁毕竟要花时间,干嘛那么麻烦?所以他们大抵想都不想,大手一挥,“换一台1.2G的去……”——那么到底该换什么?

程序员的机器通常不是很好的机器(因为穷,或者机器的历史由来已久)。换机器不是程序员所赞成的做法,但对于功能性很强的商用程序,花费钞票购买更快的机器是很有必要的,也很能解决问题。过分地追求算法的效率,改进程序,很有可能带来副作用,如影响程序的兼容性、延误程序的开发进度和推广进度、引入更隐秘的错误等等。

当然,换机器通常是商家的事,而修改代码责无旁贷地是程序员的事。

4.2 衡量程序的时间效率

统计数据总是能更好地说明问题,测试程序的时间效率需要用到精确的时间函数,Windows系统定时器的精度(只能精确到 1 s)是不够的;函数GetTickCount()只能返回到ms级的时间(而且应该是只能精确到1000/55 ms),显然也是不够的;幸运的是,Windows 9X提供了两个高精度的函数:QueryPerformanceCounter()和QueryPerformanceFrequency(),配合使用这两个函数就可以满足程序的高精度要求。

QueryPerformanceCounter()用以获得机器内部计时器的计数(单位为1 Tick),QueryPerformanceFrequency()用以获得计时器的时钟频率,所以利用两次QueryPerformanceCounter()获得的计数差值除以时钟频率,就可以计算出事件经历的精确时间,系统执行i ++的时间消耗,用这种方法就能测试到——很显然,精确度够了。

我们如此精确地统计时间主要是为了衡量程序的运行效率,因此得到内部计时器的计数就可以说明问题了,以下代码示出了i*=2与i = 1效率的比较:

输出结果如下:

嗯,不用说你也知道,移位比乘2要快。

4.3 提高程序的时间效率

提高代码的时间效率,以下是一些方案:

  • 找到程序的速度瓶颈,否则收效甚微。例如在数据库应用中,数据库连接就是个瓶颈,笔者对此深有体会。采用连接池(connection pool)将这些连接保持下来,就是一种非常好的办法;
  • 学会算法复杂度分析,优化数据结构和算法;
  • 熟悉汇编指令,优化代码。例如i++要比i = i + 1跑得快,宏比函数跑得快;
  • 牺牲空间效率,以空间换时间。很熟悉的例子是链表之于数组,链表的每个节点至少要比每个数组元素多一个指针空间(一般的为4 bytes),但使用链表做数据插入、删除,其效率是显而易见的;
  • 以内存换外存。减少系统I/O通讯的次数,适当地将数据一次性,或者流式地载入本地内存;
  • 采用cache机制。将最多最频繁的访问保存起来,这样的方法使用得很普遍,例如Internet Explorer就准备了相当部分的缓存空间,用以保存用户最近访问的网页内容;用户本地机器的域名解析工作有时候并不需要连接到DNS服务器,通过本地cache的检索也许就能迅速得到结果。当然,程序员有必要采用适当的策略以维持cache的及时更新;
  • 选择快的语言。如果选择了C/C++,同样的程序会比Java程序跑得快的多,编译程序比解释程序又要跑得快得多。但要注意,速度与兼容性常常是相矛盾的,使用了C,就意味着放弃了Java的平台无关性。
  • 尽量使用系统API(考虑兼容性的API除外)。系统API离操作系统和硬件最近,使用API可以很好地提高时间效率。

下面的例子演示了使用API的好处:

运行结果如下:

将数组每个元素的值初始化为0,最普通的办法是循环赋值,这种方法最次,要花费27 Ticks;选择C标准函数memset()可以指定内存块的初值,这种办法稍快一点,花费5 Ticks;选择系统API ZeroMemory(),它的实现功能单一,就是将某内存块清零,因此它的速度也最快,只需要4 Ticks。

话说回来,程序员不要一味地追求程序的效率,应当在满足正确性、可靠性、健壮性、可读性等质量因素的前提下,设法提高程序的效率。

5 结束语

本文内容至此作一了结,希望你有所收获。不要都吵着做项目经理,写好手边的程序先!“勿在浮沙筑高塔”,代码的问题是小问题,但同时也是大问题,代码之于软件工程正如砖瓦之于高楼建筑,做好代码的学问,做好代码的艺术,从点点滴滴做起,才能对软件产业发挥真正的作用。

注:转载文章需注明来源:VCer.net 文章地址:http://vcer.net/1290.html

  如果你觉得VCer.net不错,而且你愿意为VCer.net捐赠一元钱,那么点击后面的捐赠按钮吧:) vcer.net捐赠

1082687209616[385,308字节]

得意,我用他的代码;

自豪,他用我的代码!

[回复该贴] [加入个人书签]
[连载系列]

[1] 白乔原创:艺术编程之C++篇
[2] 白乔原创:艺术编程之C++篇[2]
[3] 白乔原创:艺术编程之C++篇[3]
[4] 白乔原创:艺术编程之C++篇[4]
[5] 白乔原创:艺术编程之C++篇[5]

[投票结果]

A: 评分 10 100% (5 票)
B: 评分 5 0% (0 票)
C: 评分 0 0% (0 票)
D: 评分 -5 0% (0 票)
E: 评分 -10 0% (0 票)

 


re:白乔原创:艺术编程之C++篇[5]

...写得非常不错,学习了!~

tanzek 于 2007-12-16 16:06:30.0 编辑 [回复该贴]

re:白乔原创:艺术编程之C++篇[5]

楼主幸苦了。好文章!

herowuking 于 2007-12-14 09:25:48.0 编辑 [回复该贴]