为了获得性能,是否值得避免多态性?

时间:2014-01-16 01:53:40

标签: c++ polymorphism

为了获得性能,是否值得避免多态性?

我在Stroustrup的书中读到多态函数调用在25%以内 比普通的函数调用更昂贵。这是否意味着我应该 尽可能避免多态性?我的意思是我应该一直在思考 类似的东西:OK多态会解决这个问题,但它可能会搞乱 性能bla bla ...或者考虑到现代CPU的强大功能,我甚至不应该这样做 敢于这么想?

6 个答案:

答案 0 :(得分:3)

  

我在Stroustrup的书中读到,多态函数调用比普通函数调用贵25%。这是否意味着我应该尽可能避免多态?

不,绝对不是!非虚拟呼叫非常快,因为呼叫本身通常是单个指令。虚拟呼叫需要额外的间接级别;这就是所谓的25%来自的地方,但那是“纯粹的开销”,即你在比较两个无参数函数的调用时所测量的。一旦开始添加参数,特别是那些需要复制的参数,两个开销之间的差距就会缩小:例如,按值将字符串传递给虚拟和非虚函数会使这个差距很难测量。 / p>

此外,只有呼叫指令本身更昂贵,而不是功能。调用函数的开销代表函数整体时序的一小部分。函数越长,调用开销所代表的百分比越小。

总的来说,您应该努力使代码易于理解。如果添加带有虚函数的子类可以更容易理解您的设计,那么无论如何都应该使用子类。运行代码的硬件每年都会变得更快,因此从长远来看,可读性会获胜。

答案 1 :(得分:3)

  

我在Stroustrup的书中读到,多态函数调用比普通函数调用贵25%。

情况可能就是这样(可能是一个球场公园),但并不重要。即使虚函数调用比普通函数调用贵25%,这仍然只是函数调用的成本,而不是函数执行的成本。我只想提高精度。函数调用的成本通常远小于函数执行的成本。但是要注意,它并不总是微不足道,如果你滥用多态并将它用于所有函数,即使是最微不足道的函数,那么额外的开销也会很快加起来。

最重要的是,必须通过函数指针调度虚函数调用,函数指针不表示内联或任何形式的跨上下文优化。这通常是大多数减速将来自的地方,即你不应该将“虚函数调用”与“函数调用”进行比较,而是将“虚函数调用”转换为“可静态分析,可能内联 - 能够,可以优化的函数调用“。

  

为了获得性能,是否值得避免多态性?

在C ++和一般的编程中,只要有价格,就会有收益,只要有收益,就有代价。就这么简单。动态多态性的代价是:(1)函数调用开销,(2)阻塞静态分析和优化,(3)经常需要堆分配的对象和额外的间接(指针,引用等),等等在,仅举几例。但是,您还可以以(1)运行时灵活性,(2)可伸缩性(问题域的不相交联合),(3)减少编译时间,(4)减少代码重复等形式获得实质性收益。 / p>

关键是,如果你想要多态性购买的东西,那么你应该使用它。但是,如果你不需要那些东西(并且你会经常感到惊讶,你不需要那些东西),那么你就不应该为此付出不必要的代价。就这么简单。

有关替代方案和权衡的更多详细信息,我建议this article

答案 2 :(得分:1)

虚拟表查找开销在“大多数”情况下不是问题。话虽这么说,如果要求效率:

  • 对于像访问者模式这样的东西,您可以使用模板化解决方案而不是基于虚拟功能的解决方案。
  • 还应该考虑静态多态,使用Curiously Recurring Template Pattern

请记住,只有当您处理“敏感”系统(如日志记录或监控界面)或需要重复调​​用不同回调的算法(例如A *或行为树)时,这才很重要。

答案 3 :(得分:0)

You Aren't Gonna Need It是应用的经验法则,在这里。

任何一个多态性实例都不太可能让你的程序慢下来,值得担心,所以当它是 immediate <的正确工具时,你应该毫不犹豫地使用多态性/ em>情况。但是,如果你将所有内容变为多态,因为可能以后会有用,那么你的程序放慢速度以至于担心,因为现在有25%(或者实际上它是什么) )惩罚适用于每个函数调用Amdahl's law不再是你的朋友。

另外,从一个程序中删除多态,要比那些没有它的程序添加多态性要困难得多。足够。添加多态是一种局部变化。删除它涉及全局搜索,以确保您获得所有实现。

答案 4 :(得分:0)

它比普通的函数调用更昂贵,但它有自己的优势。多态性是所有OO语言中最强大的东西之一。通过多态性,您可以非常轻松地实现多种设计模式,并为您节省大量时间。它使代码保持清洁,优雅,可重复使用,易于扩展和维护。这是一个很大的优势。所以这真的是一个权衡。

答案 5 :(得分:0)

与许多关于绩效/效率的问题一样,您经常需要根据具体情况对其进行评估。它可以在运行时性能和一般编程问题之间进行权衡,例如通用性和可维护性。

话虽如此,基于假设性能问题避免这种主要语言特征可能是一个坏主意。任何单个函数调用(甚至是间接函数调用)的影响都非常小。与其他典型的瓶颈相比,你必须非常频繁地调用它才能产生重大影响。

如果存在与特定函数调用相关的重大性能问题,那么(根据我的经验)对算法的其他调整往往更有用。例如,预取或缓存数据,或找到其他方法来减少调用它的频率。