计算机软件水平考试:C++Q&A:性能优化

计算机软件水平考试:C++Q&A:性能优化,第1张

计算机软件水平考试:C++Q&A:性能优化,第2张

分配大量小型类对象(如: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 次的析构函数调用。如果构造函数/析构函数都为空,这些调用将被优化掉。但如果它们有实际的事可做,这个代码将需要有限次地执行。这时,你可能要进一步通过给该数组分配原始字节来加速性能(避免构造函数/析构函数调用),然后用手工编写代码来初始化这些对象——但现在这个对你已经不成问题

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » 计算机软件水平考试:C++Q&A:性能优化

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情