分享
 
 
 

读《Efficient C++》疑惑

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

当我们进行软件开发时,如果代码比较少,我们可以很容易的掌握、了解程序的执行情况,但是当代码超过数千行,特别是达到上万行的时候,我们就很难准确掌握程序的流程,在这种情况下,进行代码跟踪是很重要的一件事情。

代码跟踪技术,对于大多数程序员来讲,就是定义一个比较简单的Trace类,将程序的信息进行输出,一般是在程序的入口写一条信息,在程序的出口写一条信息,虽然这是以时间性能为代价,但是它有助于我们在不使用调试器的情况下找到问题所在。

最极端的情况就是通过#ifdef开关,彻底消除性能开销,但是要像打开/关闭跟踪,必须重新编译,显然程序的最终用户无法这么做。所以只有通过动态的与程序通信来进行跟踪控制。

首先,为了能够获得程序执行时间,我们先自己定义一个简单的测试性能的类,名字就叫做Timer,实现如下:

class Timer

{

public:

Timer():start(clock()) {}

~Timer() { cout<<"The time is :"<<clock()-start<<endl; }

private:

clock_t start;

};

接下来,我们就要定义一个简单的跟踪类Trace,初步实现如下:

class Trace

{

public:

Trace(const string& name);

~Trace();

static bool trace_active;

private:

string theName;

};

bool Trace::trace_active=false;

inline Trace::Trace(const string& name):theName(name)

{

if(trace_active)

cout<<"Enter the function:"<<name<<endl;

}

inline Trace::Trace(const char* name):theName(name)

{

if(trace_active)

cout<<"Enter the function:"<<*name<<"ms"<<endl;

}

inline Trace::~Trace()

{

if(trace_active)

cout<<"Exit the function:"<<theName<<endl;

}

接下来我们进行测试,先定义一个简单的函数:int f(int x) { return x+1; }

先测试不跟踪的时间开销:

int main()

{

Timer* time=new Timer;

Trace::trace_active=false;

for(int i=0; i<1000000; ++i) f(i);

delete time;

return 0;

}

输出时间是30ms。

接下来,我们打开跟踪功能: int f(int x) { Trace trace("f"); return x+1; } Trace::trace_active=false;

同时把I/O关闭,再次测试,结果如下:1892ms

这里我们看到了时间提升了62倍,主要的性能来源就是(1)在构造函数中"f"要转换成string类型,(2)theName的构造和析构。似乎各自影响了1/3的效率,是不是这样呢?

下面,我们取消"f"要转换成string类型的开销:增加一个构造函数:

Trace(const char* name):theName(name)

{

if(trace_active)

cout<<"Enter the function:"<<name<<"ms"<<endl;

}

再次进行测试,结果如下(关闭I/O):1690ms

性能的提高似乎并不像我们预期的那样高,为什么呢?难大是if(trace_active)影响了测试结果?我们再把这条判断语句关闭,再次进行测试,结果如下:1646ms。

还是差了一些,并不是1/3的数据,是不是参数传递的影响?这次我们把theName也拿掉,看看类本身到底占用了多少时间,再次测试,结果如下:153ms。

分析以上数据:类本身的参数传递等占用了153ms,if判断语句占用了44ms,theName的构造和析构占用了1493ms,"f"转换成string占用了202ms,所以我们的主要目标应该集中在theName上面,下面我们用组合取代聚合,看看性能的变化:

class Trace

{

public:

Trace(const string& name);

~Trace();

static bool trace_active;

private:

string* theName;

};

bool Trace::trace_active=false;

inline Trace::Trace(const string& name)

{

if(trace_active)

{

cout<<"Enter the function:"<<name<<endl;

theName=new string(name);

}

}

inline Trace::Trace(const char* name)

{

if(trace_active)

{

cout<<"Enter the function:"<<*name<<"ms"<<endl;

theName=new string(name);

}

}

inline Trace::~Trace()

{

if(trace_active)

{

cout<<"Exit the function:"<<*theName<<endl;

delete theName;

}

}

测试结果是2682ms,和我们采用聚合相比,时间增加了58.70%,看来在堆上创建对象开销的确很大。但是书上说,这时候,时间反而减低了一个数量级,这是我不能够理解的,如果有谁看过这本书,烦请告知一下,谢谢了!

结论:从上面的分析,我们可以看出对于一个很小的函数,更总的开销相对来说很大,影响了程序的性能。所以适合内联的,就不适合跟踪,Trace对象不应该添加到频繁使用的小函数中。

注:以上数据是在dev-C++ 4.9.5.0,win2000下,每组数据测试了10次,取平均值得到的。另外,在上面的数据测试过程中,我始终没有打开I/O,原因是I/O太消耗时间了,不信,你打开看看。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有