Performance 面向接口而非实现的编码是否意味着性能受到影响?

Performance 面向接口而非实现的编码是否意味着性能受到影响?,performance,oop,interface,Performance,Oop,Interface,在日常的程序中,我甚至不会去考虑根据接口而不是实现进行编码可能会对性能造成的影响。好处在很大程度上超过了成本。所以请不要对好的OOP给出一般性的建议 尽管如此,XNA(游戏)平台的设计者在文章中给出了他的主要论点,即没有针对一个可能会影响性能的接口设计框架的核心类。在游戏开发的背景下,每一个fps都有可能起作用,我想问问自己这是一个合理的问题 有人有这方面的数据吗?我看不到一个好的方法来测试/衡量这一点,因为我不知道这样一个游戏(图形)对象会给我带来什么影响。在我个人看来,当涉及到图形时,所有真

在日常的程序中,我甚至不会去考虑根据接口而不是实现进行编码可能会对性能造成的影响。好处在很大程度上超过了成本。所以请不要对好的OOP给出一般性的建议

尽管如此,XNA(游戏)平台的设计者在文章中给出了他的主要论点,即没有针对一个可能会影响性能的接口设计框架的核心类。在游戏开发的背景下,每一个fps都有可能起作用,我想问问自己这是一个合理的问题


有人有这方面的数据吗?我看不到一个好的方法来测试/衡量这一点,因为我不知道这样一个游戏(图形)对象会给我带来什么影响。

在我个人看来,当涉及到图形时,所有真正繁重的工作都会传递给GPU。这样可以释放CPU来做其他事情,比如程序流和逻辑。我不确定当编程到一个界面时是否会影响性能,但考虑到游戏的本质,它们不需要扩展。也许是某些类,但总的来说,我不认为游戏需要在编程时考虑可扩展性。因此,继续编写实现代码。

对接口进行编码总是会更容易,因为接口如果做得好,会更简单。使用接口编写正确的程序显然更容易

正如古老的格言所说,让一个正确的程序快速运行要比让一个快速的程序正确运行容易得多


因此,对接口编程,让一切正常工作,然后进行一些分析,以帮助您满足任何性能要求。

我认为对象生存期和您创建的实例数量将提供一个粗略的答案

如果你说的是有数千个实例、生命周期短的东西,我想最好是用结构而不是类来实现,更不用说用类来实现接口了


对于像这样的组件,实例数量少,生命周期中等到较长,我无法想象它会有多大的不同。

首先,我要说的是,一般的概念是程序员的时间通常更重要,当实施发生变化时,反对实施可能会迫使更多的工作

第二,使用适当的编译器/Jit,我假设使用接口比使用实现本身花费的额外时间少得可笑。 此外,模板等技术可以从运行中删除接口代码

第三,引用Knuth的话:“我们应该忘记小效率,比如说97%的时间:过早优化是万恶之源。”
所以我建议先编码好,只有当你确信接口有问题时,才需要考虑改变。

也可以假设,如果这个性能是正确的,大多数游戏都不会用C++来使用OOP方法,但情况并非如此,这就有点说明了。 很难笼统地谈论测试,一个糟糕的程序可能会在糟糕的接口上花费大量时间,但我怀疑这是否适用于所有的程序,所以你真的应该看看每个特定的程序。

静态调用、实例调用、虚拟调用或接口调用的原始成本似乎没有显著差异

这取决于有多少代码在编译时内联或未内联,这可以将性能提高5倍

编写接口代码也需要更长的时间,因为您必须编写合同(接口),然后编写具体的实现

但用正确的方式做事总是需要更长的时间

这将意味着一个性能打击


设计者应该能够证明自己的观点。

接口通常意味着对性能的一些影响(但这可能会根据所使用的语言/运行时而变化):

  • 接口方法通常通过编译器的虚拟调用来实现。正如另一位用户指出的,编译器无法内联这些内容,因此您将失去潜在的收益。此外,他们至少会添加一些指令(跳转和内存访问),以便在代码段中找到合适的PC
  • 在许多语言中,接口也意味着一个图,需要一个DAG(有向无环图)来正确管理内存。在各种语言/运行时中,通过使用循环图,实际上可以在托管环境中获得内存“泄漏”。这(显然)给系统中的垃圾收集器/内存带来了很大的压力。注意循环图
  • 一些语言使用COM风格的接口作为其底层接口,每当接口被分配给本地或按值传递给函数(用于生命周期管理)时,自动调用AddRef/Release。这些AddRef/Release调用可能会累加起来,成本相当高。一些语言已经考虑到了这一点,并且可能允许您以“const”的形式传递一个接口,该接口不会自动生成AddRef/Release对来减少这些调用
  • 这里是一个循环图的小示例,其中两个接口相互引用,并且都不会自动收集,因为它们的引用计数始终大于1

    interface Parent {
      Child c;
    }
    
    interface Child {
      Parent p;
    }
    
    function createGraph() {
      ...
      Parent p = ParentFactory::CreateParent();
      Child c = ChildFactory::CreateChild();
    
      p.c = c;
      c.p = p;      
      ...  // do stuff here
    
      // p has a reference to c and c has a reference to p.  
      // When the function goes out of scope and attempts to clean up the locals
      // it will note that p has a refcount of 1 and c has a refcount of 1 so neither 
      // can be cleaned up (of course, this is depending on the language/runtime and
      // if DAGS are allowed for interfaces).  If you were to set c.p = null or
      // p.c = null then the 2 interfaces will be released when the scope is cleaned up.
    }
    

    IMO是的,但出于一个基本的设计原因,它比虚拟分派或类似COM的接口查询或运行时类型信息所需的对象元数据或诸如此类的东西要微妙和复杂得多。所有这些都有相关的开销,但这在很大程度上取决于所使用的语言和编译器,还取决于优化器是否能够在编译时或链接时消除此类开销。然而,在我看来,编码到接口还有一个更广泛的概念上的原因