虚函数所造成的性能损失

假设在一个线程同步环境中,有类似下面所示的代码段:

//进入线程同步

nNum++;

//退出线程同步

以win32为例,如我们所知,线程同步工具有临界区,互斥体,信号量。我们可以任意选择一个,为了简单很可能我们就选择了临界区。假如我们需要同步的代码非常简单,我非常建议不需要使用c++的任何功能。但是,很可能没这么幸运,很可能你的代码会被很多人修改,很可能同步的时候需要异常退出,很可能同步的里面还有点逻辑处理,很可能你在退出的时候没有释放锁。那么你就悲剧了。

C++在这里一点上就体现出了与生俱来的优势,构造函数和析构函数。假如我们把获得锁写进构造函数里面,释放锁写进析构函数里面,就能保证任意情况的退出之前都能够释放锁,从而不会造成死锁。

还有个问题是我们应该如何实现这些不同的同步工具。如果,我们分别写三个类,CCriticalSection,CMutex,CSemaphore,这三个类不是继承自同一个基类的,而且这三个类里面也没有任何的虚函数,而且我们把操作都写成内联的。那么,在效率上与直接用C相比基本没有差别。因为,所有额外的调用开销都内联了。在不丧失效率的同时保持了灵活性,这确实是非常强大的地方。

万一你说为了灵活性,需要让这三个类继承同一个基类,CBaseLock,同时需要把析构函数定义成虚的,这样就会造成很多额外的性能损失。比如,可能需要构造和析构基类对象,需要初始化虚函数指针,执行阶段需要通过虚函数指针间接调用,还有一个最重要的损失,编译器无法内联虚函数,如果虚函数比较小,那么相对于原来的情况,这是一个巨大的性能损失。某种意义上,我们可以忽视,基类对象的构造和析构,以及虚函数指针的初始化和调用时刻的间接寻址,因为这些可以其它方面的因素来抵消。

但是,无法内联一个小的函数所造成的额外开销是很大的。想象一下,比如刚才几个类里面的析构函数只是释放锁这一个操作,肯定是可以内联的,但是现在写成虚函数了,就无法内联了,如果这个函数被调用很多次,比如几百万次,和原来消耗的时候相比,肯定是天壤之别了,因为原来没有函数调用开销,现在有,而且因为函数内部操作太少了,函数调用开销所占据的比例非常大,所以你的设计造成了巨大的性能损失。

本文的观点主要来自提高C++性能的编程技术一书,欢迎吐槽。

http://www.xpc-yx.com/2012/11/13/%e8%99%9a%e5%87%bd%e6%95%b0%e6%89%80%e9%80%a0%e6%88%90%e7%9a%84%e6%80%a7%e8%83%bd%e6%8d%9f%e5%a4%b1/

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值