性能损失与C ++接口的工作?(Performance penalty for working wi

2019-06-14 17:09发布

是否有C ++使用接口(抽象基类)时的运行时性能损失?

Answer 1:

答案很简单:第

龙答:这不是基类或祖先的类在其层次结构,影响它的速度的数量。 唯一的一点是方法调用的成本。

非虚拟方法调用具有成本(但可以被内联)
虚拟方法调用具有成本稍高,因为你需要仰视你怎么称呼它(但是这是一个简单的表查找不是搜索)之前调用该方法。 由于在接口上的所有方法都是通过定义虚拟存在这笔费用。

除非你正在写一些超速度感应应用中,这不应该是一个问题。 额外的清晰度,你将使用一个接口收到通常弥补了任何感知的速度下降。



Answer 2:

使用虚拟调度函数调用不内联

有一种惩罚虚函数这是很容易忘记:虚拟呼叫不能在(公共)的情况,其中内联对象的类型是不知道的编译时间。 如果你的函数小,适用于内联,这个点球可能非常显著,因为你不仅是增加一个调用的开销,但是编译器也被它如何能优化调用函数的限制(它必须承担可能的虚拟功能已经改变了一些寄存器或存储器位置,它不能传播的主叫用户和被叫之间的恒定值)。

虚拟呼叫成本取决于平台

至于比较普通的函数调用的调用开销处罚,答案取决于你的目标平台上。 如果你的目标与在x86 / x64 CPU一台PC,则判为调用虚函数是很小的,因为现代的x86 / x64的CPU可以间接调用执行分支预测。 但是,如果你的目标一个PowerPC或其它一些RISC平台,虚拟呼叫处罚可能是相当显著,因为间接调用从未在某些平台上(参看预测PC / Xbox 360的跨平台开发最佳实践 )。



Answer 3:

有每个虚拟函数调用一个小小的惩罚相比于常规呼叫。 你是不可能,除非你正在做几十万每秒调用来观察差别,而价格往往是值得无论如何付出添加代码清晰。



Answer 4:

当你调用虚函数(通过一个接口说)程序有做功能的一个查找表,看哪个函数调用该对象。 这给出了一个小小的惩罚相比,直接调用该函数。

此外,当您使用一个虚函数,编译器不能内联函数调用。 因此,有可能是一个点球使用虚拟功能对于一些小的功能。 这通常是最大的性能“打”,你可能会看到。 这真的只是一个问题,如果该函数是小且多次调用,从一个循环内说。



Answer 5:

这是适用于某些情况下,另一种选择是编译时多态性与模板。 当你想一个实现选择在节目的开头,然后用它来执行的时间是非常有用的,例如,。 用运行时多态性的例子

class AbstractAlgo
{
    virtual int func();
};

class Algo1 : public AbstractAlgo
{
    virtual int func();
};

class Algo2 : public AbstractAlgo
{
    virtual int func();
};

void compute(AbstractAlgo* algo)
{
      // Use algo many times, paying virtual function cost each time

}   

int main()
{
    int which;
     AbstractAlgo* algo;

    // read which from config file
    if (which == 1)
       algo = new Algo1();
    else
       algo = new Algo2();
    compute(algo);
}

同样使用编译时多态性

class Algo1
{
    int func();
};

class Algo2
{
    int func();
};


template<class ALGO>  void compute()
{
    ALGO algo;
      // Use algo many times.  No virtual function cost, and func() may be inlined.
}   

int main()
{
    int which;
    // read which from config file
    if (which == 1)
       compute<Algo1>();
    else
       compute<Algo2>();
}


Answer 6:

我不认为,成本比较虚函数调用和直线函数调用之间。 如果你正在考虑使用抽象基类(接口),那么你必须要执行基于动态类的一个对象的几个动作的一个情况。 你必须做出这样的选择不知何故。 一种选择是使用虚拟功能。 另一种方法是对对象的类型的开关,无论是通过RTTI(潜在昂贵的),或添加型()方法将基类(潜在地增加了存储器使用的每个对象的)。 因此,虚函数调用的成本应该是比较替代的成本,而不是无所事事的成本。



Answer 7:

大多数人注意的运行时间延长,这是正确的。

然而,在我的经验,在大型项目,从接口清晰和正确封装的好处迅速弥补速度的增益。 模块化的代码可以换成改进的实现,所以最终的结果是一个大的增益。

您的里程可能会有所不同,这显然取决于你开发的应用程序。



Answer 8:

应该注意的一件事是,虚函数调用的成本可以从一个平台到另一个平台。 在控制台上,他们可能会更明显,因为通常虚函数表调用意味着高速缓存未命中,并且可以拧分支预测。



Answer 9:

需要注意的是多重继承腌多虚表指针的对象实例。 随着G ++在x86上,如果你的类有一个虚拟的方法,并没有基类,你有一个指针的vtable。 如果你有虚方法一个基类,你仍然有一个指针的vtable。 如果你有虚方法两个基类,你必须在每个例如 两个虚函数表的指针。

因此,多重继承(这是在C ++中实现接口的),你付出的对象实例大小基类指针倍大小。 在内存占用的增加可能有间接影响性能。



Answer 10:

在C ++中使用抽象基类一般要求使用一个虚函数表中,所有的接口调用要通过该表进行查找。 相比于原始函数调用的成本是很小的,所以要确保你必须去比速度更快担心它。



Answer 11:

我所知道的唯一的主要区别是,因为你没有使用一个具体的类,内联是(多少?)做起来难。



Answer 12:

我能想到的唯一的事情就是虚拟的方法是稍微慢于非虚方法调用,因为调用要经过的虚方法表 。

然而,这是一个不好的原因搞砸了你的设计。 如果你需要更多的性能,使用更快的服务器。



Answer 13:

至于包含虚拟函数的任何类,使用虚表。 显然,通过调度机制,就像一个虚函数表调用一个方法比直接调用速度较慢,但​​在大多数情况下,你可以忍受的。



Answer 14:

是的,但没有值得一提的,据我所知。 对性能的影响是因为“间接”你在每个方法调用的。

然而,这真的取决于你所使用的编译器,因为一些编译器不能内联从抽象基类继承的类中的方法调用。

如果你想确保你应该运行自己的测试。



Answer 15:

是的,有一个点球。 这可以提高你的平台上表现的东西是使用非抽象类,没有虚函数。 然后用一个成员函数指针到非虚拟函数。



Answer 16:

我知道这是一种罕见的观点,但即使提的这个问题让我怀疑你把太多想进级结构。 我见过许多系统是有太多的“抽象级别”,这本身使他们容易出现严重的性能问题,方法调用的不是由于成本,但由于趋势进行不必要的调用。 如果这种情况发生在多个层次,这是一个杀手。 看一看



文章来源: Performance penalty for working with interfaces in C++?