• 网络学院
  • IT资讯
  • 操作系统
  • 网络技术
  • 软件应用
  • 办公软件
  • 编程技术
  • 网站架设
  • 数据库类
  • 平面设计
  • 多媒体类
  • 游戏资讯
  • 教学论文
  • 认证考试
C++Q&A:性能优化
  站点:
  • 首 页
  • 最新软件
  • 文章教程
  • 国内软件
  • 国外软件
  • 绿色软件
  • 源码下载
  • 字体下载
C++Q&A:性能优化
软件发布 C++Q&A:性能优化
网络软件 系统工具 应用软件 联络聊天 图形图像 多媒体类 行业软件 游戏娱乐 编程开发 安全相关 教育教学 数码软件 绿软下载
热门软件: QQ 瑞星 pplive e话通 木马克星 千千静听 office2000 五笔字根 Photoshop 视频分割
返回文章教程首页 >> 文章首页 >> 认证考试 >> 系统工程师 >> C++Q&A:性能优化

C++Q&A:性能优化

添加时间: 2007-4-9 2:42:19  作者: 系统工程师认证参考  阅读次数:29   来源: http://www.d9soft.com

       

 
 分配大量小型类对象(如:10,000小型记录)最快和最佳方法是什么? 当然,mfc 序列流化对象可以完成所需的任务。但是,内存的分配和销毁相当耗时。有没有办法对此进行改进?
  我无法告诉你最好的方法,因为那取决与应用程序的具体情况和其使用方式。性能和内存分配是如此巨大的一个主题,有关它们已经有很多很多书籍。没有哪一种方案适合所有的情形。最优化总是需要在速度和其它资源之间进行明智的权衡。例如,如果你愿意建立巨型索引,那么就会获得非常快的查询速度。或者要想显示速度快,那么就得以加载时间作为代价。因此,本文我只能就某些需要考虑的问题给你提供一个概述,以及提供一些工具和途径以帮助你自己找到答案。
  如果你觉得程序的性能不太满意,首先必须确定瓶颈在哪,对此要有清醒的认识。你可以借助复杂的工具(profiler)来产生各种有关性能的报告,但如果只是想知道你的代码在哪里耗时,那么用一些自己编写的简单工具即可,我写了一个类叫 showtime,它可以报告代码的某些部分执行时要花费多长时间。为了使用它,你只需在要用时钟的代码块起始处实例化一个 showtime 堆栈对象即可:


void calculatepi()
{
   showtime st("calculating pi");
   // do it
}
这段代码将产生一个象下面这样的 trace 信息:
calculating pi: 342 msec
  showtime 是如何工作的呢?它为智能指针以及在代码块起始处和末尾处你想做某些自动处理的地方使用常见的 c++ 构造函数/析构函数(ctor/dtor)模式。showtime 的构造函数将时钟时间(自从进程启动后的时钟嘀嗒数)保存在某个数据成员中;析构函数则用从最后的时钟数中减去这个时钟数并产生一条信息。由于构造函数/析构函数是在代码块的起始处/末尾处调用的,这样便测算出总共用了多少时间。代码如 figure 1 所示。
  showtime 并不太复杂。比如,它并不考虑多线程的情况,并且也不报告在每个函数中某个工具消耗了多少时间。但是对于日常使用来说,它能给你提供应用程序在何处耗时的很好的参考。不要忘记针对 release 版本进行性能测试!毕竟那是你交付使用的版本。此外,release 和 debug 版本之间的差别可能会曲解你的结果。例如,依赖你的设置方式,debug 版本也许要进行额外的堆栈 检查 ,这样便使应用程序性能下降。由于在 release 版本中没有 trace 信息,所以我添加了另外一个类,perflog,它可以将性能统计定向到一个文本文件:

// open log file
perflog mylog("myresults.log");  现在 showtime 可以将信息写入myresults.log文件以及trace流。但是,不要忘了在交付程序之前去掉这个性能监视。
  有了 showtime 在手,我可以开始回答你的问题了。我写了一个小程序,perftest,这是一个典型的具备文档的 mfc 文档/视图应用,它使用三种不同的方法分配具有 20,000 条定长记录的链表。
  方法一是典型的 mfc 方式。链表的实现使用 mfc 的 coblist,链表中的每个项目使用单独的表单元。每个表单元只是小小结构,此结构保存指向上下单元的指针和对象本身。所以 coblist 的每一项由12个字节的开销,但是,如果你需要几个表指向相同项目的话,就必须要有几个表单元。(例如,你想用不同的方法排序对象)。
  方法二表示了第一个性能上的改进。这里记录本身存储下一条记录的指针,所以没有单独的表单元。这个方法在仅有一个链表的情况下才成为可能——也就是说,如果你不需要用几个链表来指向以不同方式排序的相同对象。在这样情况下,使用数组可能更有效。但即便是一个链表,如果要经常修改顺序,链表也比数组要快,因为修改指针比在内存中移动对象要快。
  方法一和方法二都是每分配一个记录/对象单独调用一次 new 操作符。如果你分配20,000个对象,便调用20,000次 new 操作。方法三用单个数组一次性分配所有的 20,000 个对象:


m_array = new cmyrecord[20000];        记录的链接则是通过设置每条记录中指向下一条记录的指针域实现的。分配的速度快,因为只有一次函数调用,但它需要一块连续的足以容纳 20,000 条记录的内存块。当然,编译器仍然要保证对象的初始化。当你用向量形式的 new 操作,编译器产生代码来调用每个对象的构造函数,因此有20,000次的构造函数调用。同样,在 delete [] 操作中会有 20,000 次的析构函数调用。如果构造函数/析构函数都为空,这些调用将被优化掉。但如果它们有实际的事可做,这个代码将需要有限次地执行。这时,你可能要进一步通过给该数组分配原始字节来加速性能(避免构造函数/析构函数调用),然后用手工编写代码来初始化这些对象——但现在这个对你已经不成问题。

  还有一种办法是整个类的分配性能改进策略——我只将它提出来,不作进一步的探讨——这个方法重载new操作符,如下所示:

class cmyrecord {
public:
  void* operator new (size_t nbytes) {
    return fancyalloc(nbytes);
  }
  void operator delete (void* p) {
    fancyfree(p);
  }
};   你可以按照自己的意愿实现 fancyalloc 和 fancyfree,只要它们按照正确的大小分配/释放内存块。如果你有一个在程序中全程使用的特殊对象,最常用的技巧之一是维护一个释放(free pool)对象池。而不是去调用 free,你的 delete 操作符将释放的对象添加到一个叫释放池的链表中。然后分配器调用malloc之前在此释放池中查找对象。这样做可以使分配/释放操作极其快速,但你必须小心行事,使用内建的分配器而不能越雷池一步,大多数情况下它表现得相当不错。
  不管怎样,就像我开始所说的那样,有关内存分配的详细内容已经超出本专栏讨论的范围。你可以使用的技巧数不胜数。我之所以选择这三种方法,并不是因为它们如何棒,而是举例说明你可以用来优化程序的几种方式。
  为了搞清楚哪种方法最快,关键的问题是:你要什么东西快?如果你关注的是内存分配,那么你觉得方法一(coblist)最慢,因为它分配的对象最多,而方法三(成块的分配)最快,因为它一次性地分配。但是对于读写操作又如何呢?每一种方法都暗示了不同的序列化策略。对于方法一和方法二来说,每条记录单独调用 cmyrecord::serialize 来序列化(参见 figure 2),对于方法三而言,我
猛的一下写入整个数组。还要说明一点,这是个很武断的做法,我只用它了做教育目的。就像方法二那样,我可以轻松地像序列化单条记录那样序列化巨型数组。注意在实现非正统的序列化策略时,做起来会稍微复杂一些。
  任何时候序列化包含指针的数据时,必须要将指针转换成在磁盘上有意义的东西,因为数据被实际加载到的位置与下次读取该文件的内存位置正好完全相同的几率是非常低的。就像你不买彩票而想中奖的几率一样。mfc 实现了许多神奇的操作对指针和磁盘ids进行来回转换。对于 perftest,我以链表顺序保存记录,因此不需要ids。我可以简单地在它被加载后进行重链(方法二和方法三)。当然,这意味着如果你改变链表顺序,则方法三将失败(我已经隐含假设该链表就是一个数组)。
  最后,另一个序列化问题是:你打算序列化的记录是定长的还是可变长度的?cmyrecord 含有 64个字符的数组。cmyrecord::serialize 使用 carchive::readstring/writestring 来序列化用到的字符,而不是所有的 64 个字符。如果字符串是“foo”,则它只序列化4个字符(“foo”加结尾必须的“ ”)。方法三写入整个数组。它序列化所有字符,即使字符串为空。这样是不是很浪费呢?要看情况。如果字符串是10个字符的电话号码或16位字符的信用卡号码,大多数记录可能都会补足字符,因此序列化所有内容也许没什么问题。但如果字符串是一个地址或可选的字段,那么磁盘上可能会有成兆字节的零。那就好考虑了。这不仅仅是磁盘空间的浪费,而且速度也会受影响,因为它要花更多的时间来读/写更多的字节。方法三一次性读/写整个表——那它真的就更快吗?
  为了找到答案,我在 perftest 中使用 showtime 对象来显示不同的操作要花多长时间。我运行这个程序,创建一个新文件,保存它又读取它,然后退出。figure 3 显示了 showtime 产生的日志,
其中有注解解释其操作。像期望的那样,方法一(coblist)分配是最慢的(130ms),方法三最快(70ms)。销毁释放对象差别更为明显。那么序列化又如何?对于写入操作,方法二和方法三差别不大——分别为60和61ms。显然一次性写操作争取的时间是以写入太多数据为代价的——方法二是 536kb,方法三是庞大的 2.9mb。(我写了另一个类,showfileused,这个类报告序列化期间存档 cfile 开始和结束位置之间的差别)。对于读取操作,方法三比较快,但同时也有一个磁盘缓冲副作用——这是当你着手性能测试时,另一个必须考虑的因素。
  showtime 提供原始的性能数据,但你必须对它们进行解释,以便通俗易懂。使用 coblist (方法一)分配所用的时间几乎是方法三大块数组分配所用时间的两倍——但不知是否有人注意到没有,它用 70ms 的时间来打开一个文件?从字面上讲是一眨眼的功夫。那大块读取所节省的时间确实值得以五倍的磁盘空间为代价吗?对于 perftest 来说,答案肯定是,no。对于其它的一些应用,答案可能是yes。底线是必须经过试验才能确定。你总是可以使自己的程序更快,但通常只能以其它资源为代价,像内存、磁盘空间、复杂性(解释为可靠性、健壮性和程序员小时数)或其它方面的速度。性能优化是一种艺术。技巧是充分理解你的应用程序,并购买或编写一些工具,这些工具是你能了解应用程序到底在干什么。你也许会对所发现的事情感到惊讶。

 

上下文章:

 

上一篇文章: C++Q&A:控件和组件概念浅析 下一篇文章: 封装的变化之不断变化的需求

相关文章:

  • Vista系统的官方优化指南文档下载
  • 上网高效率 宽带路由优化技巧放送
  • ORACLE考试 Oracle8i : 性能及其调优 大纲
  • 优化Oracle网络设置的方案
  • Oracle数据库性能保护(下)

相关软件:

  • windows XP 注册表优化文件reg下载
  • windows 2000 注册表优化下载
  • Windows优化大师 V6.9 Build 5.1209
  • 联想公司的widows XP优化工具
  • SpeedNeed宽带网优化 V4.2 版
  • Registry Help Pro(注册表优化和修复) v1.15 绿色版

 

快速导航

  • 网络学院
  • 精品汇聚
  • 字体下载
  • 教程下载
  • ASP源码
  • PHP源码
  • Net源码
  • JSP 源码

认证考试分类导航

  • 微软认证
  • 计算机等级考试
  • 软件水平考试
  • 思科认证
  • Oracle认证
  • Linux认证
  • JAVA认证
  • 网络工程师
  • 系统工程师
  • 程序员

本类经典文章推荐

  • SQLServer的安全检查
  • 系统设计师资格与水平考纲 (原高级...
  • 系统分析员备考之ISO9000系列基础...
  • 开发数据库的WEB查询
  • 在builder中向Excel传递数据
  • 用Powerbuilder开发WEB数据库
  • PowerBuilder制作IE风格的图标按钮
  • PowerBuilder编程技巧四则
  • 小议数据库主键选取策略
  • 跨数据库文献检索统一平台的实现

系统工程师阅读排行

  • 数据库原理各章节简答题总结
  • 利用C++Builder6.0开发简单的车辆...
  • 跨数据库文献检索统一平台的实现
  • 用Powerbuilder开发WEB数据库
  • 系统设计师资格与水平考纲 (原高级...
  • 项目进度的黑洞——已完成90%
  • 系统分析员备考之ISO9000系列基础...
  • 小议数据库主键选取策略
  • 数据库系统工程师全真预测试卷(一...
  • 2005年上半年数据库系统工程师上午...

认证考试阅读总排行

  • 全国计算机等级考试一级模拟试题01
  • 全国计算机等级考试一级模拟试题10
  • 全国计算机等级考试一级模拟试题08
  • MCSD简介
  • 全国计算机等级考试一级考试最新模...
  • 全国计算机等级考试一级模拟试题07
  • 全国计算机等级考试一级模拟试题02
  • 全国计算机等级考试一级模拟试题06
  • 全国计算机等级考试一级模拟试题03
  • 一级(WINDOWS)试题解析-Word篇

广告位置

字母检索 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 回到顶部

关于我们 | 版权声明 | 免责条款 | 广告联系 | 软件发布 | 下载帮助 | 下载排行 | 网站地图 | 特别鸣谢 | 友情连接

copyright; 2005-2008 D9soft.com 第九软件网 版权所有