2009-05-06 15 views
5

在日常的程序中,我甚至不会考虑编写接口而不是实现的可能性能。这些优势大大超过成本。所以请不要提供有关良好OOP的通用建议。尽管在this的帖子中,XNA(游戏)平台的设计者给出了他的主要论点,他没有将他的框架的核心类设计为一个接口,这意味着性能会受到影响。看到它是在游戏开发的背景下,每个fps可能都很重要,我认为这是一个有问题的问题。对接口进行编码而不是实现意味着性能受到影响?

有没有人有任何统计数据?我没有看到一个很好的方法来测试/衡量这一点,因为不知道我应该记住这样一个游戏(图形)对象的影响。

+0

你的问题仍然有效,但你错误地引用了这个人。他在说,提供接口*仅仅是为单元测试提供模拟方式*并不值得。我可以看到他的观点。 – 2009-05-06 08:20:46

+0

我不知道。它可以提供多少击打?什么是值得你能够测试的东西? – 2009-05-06 10:05:28

回答

2

接口通常意味着几命中性能(这但是可以根据所用的语言/运行时改变):

  1. 接口方法通常通过由编译器的虚拟呼叫实现。正如另一位用户指出的那样,编译器不能将它们内联,这样就失去了潜在的收益。此外,他们至少添加一些指令(跳转和内存访问)以获取代码段中正确的PC。
  2. 接口,在不同的语言,也暗示的曲线图,并且需要DAG(有向无环图)正确地管理存储器。在各种语言/运行时间中,通过创建循环图,您实际上可以在托管环境中获得内存“泄漏”。这对系统中的垃圾收集器/内存施加了很大的压力(显然)。注意循环图!
  3. 一些语言使用COM风格界面作为其底层接口,自动调用每当接口分配到本地,或通过了值的函数(用于生命周期管理)的AddRef /释放。这些AddRef/Release调用可以加起来并且相当昂贵。一些语言已经考虑到了这一点,并且可能允许你将接口作为'const'传递,这将不会自动生成AddRef/Release对,从而自动减少这些调用。

这里是2个接口相互引用和既不会自动被收集为他们的引用计数将总是大于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. 
} 
0

以我个人的观点来看,当涉及到图形的时候,所有非常繁重的工作都会转移到GPU上。这些可以释放你的CPU来完成程序流和逻辑等其他功能。我不确定在编程到界面时性能是否受到影响,但考虑到游戏的性质,它们不是可扩展的。也许某些课程,但总体而言,我不认为游戏需要考虑可扩展性进行编程。所以继续,编码实现。

+0

可扩展性不是很好(尽管我可以为它做一个例子),但可测试性是我的主要牛肉。请参阅http://stackoverflow.com/questions/804904/xna-mock-the-game-object/828482#828482 – 2009-05-06 07:54:47

6

编码到接口总是会更容易,只是因为接口,如果做得好,就简单多了。它明显更容易使用接口编写正确的程序。

而且,正如旧格言所言,更容易使正确的程序运行得比使快速程序正确运行更快。

所以编程接口,让一切正常,然后做一些分析,以帮助你满足你可能有的任何性能要求。

+0

但我没有得到设计的XNA框架,所以没有可用的接口.. – 2009-05-06 07:56:16

+1

所以在这种情况下,你别无选择,所以任何比较都是没有意义的。 – PaulJWilliams 2009-05-06 07:57:57

+0

+1为格言和坚实的建议 – annakata 2009-05-06 08:03:04

1

我认为对象的生命周期和你创建的实例的数量将提供一个粗粒度的答案。

如果你正在谈论的事情会有成千上万的实例,而且生命期短,我猜想用结构而不是类可以做得更好,更不用说实现接口的类。

对于更类似组件的情况,实例数量少且寿命适中,我无法想象它会产生很大的变化。

3

首先我想说的是,普遍的观点是程序员的时间通常更重要,而当实现发生变化时,对付实现可能会迫使更多的工作。

其次,使用适当的编译器/ Jit我会认为与接口实现本身相比,使用接口的时间少得多。此外,像模板这样的技术可以从运行中删除接口代码。

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

另外我会假设如果这个性能命中是真的,大多数游戏都不会使用OOP方法与C++,但事实并非如此,这个Article详细阐述了一点。

很难以一般形式谈论测试,当然一个糟糕的程序可能会花费很多时间在糟糕的界面上,但我怀疑这是否适用于所有程序,所以你应该看看每个特定的程序。

3

What Things Cost in Managed Code

“有没有出现是在一个静态调用,实例调用,虚拟呼叫,或接口调用的原料成本显著的差异。”

这取决于有多少你的代码被内联或在编译时间,这可以提高性能〜5倍。

它也需要更长的时间来代码,接口,因为你要在合同(接口),然后在具体实现代码。

但是做事情的正确方法总是需要更长的时间。

0

这将意味着一个性能命中

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

1

IMO肯定的,但对于更大的环状图形的一个小例子基本的设计原因比虚拟调度或COM类接口查询或运行时类型信息所需的对象元数据或类似的东西更加微妙和复杂。所有这些都有相关的开销,但它在很大程度上取决于所使用的语言和编译器,还取决于优化程序是否可以在编译时或链接时消除这种开销。然而,在我看来,有一个更广泛的概念之所以编码到一个接口蕴含(非保证)性能的下降:

编码到一个接口意味着有你和 之间的屏障你想要的具体数据/存储访问和转换。

这是我看到的主要原因。作为一个非常简单的例子,假设您有一个抽象图像接口。它完全抽象出其像素格式的具体细节。这里的问题是,最高效的图像操作通常需要那些具体的细节。我们无法使用高效的SIMD指令来实现我们的定制图像过滤器,例如,如果我们必须一次一个地删除getPixel,并且一次只删除一个,而忽略底层的像素格式。

当然,抽象图像可以尝试提供所有这些操作,并且这些操作可以非常有效地实现,因为它们可以访问实现该接口的具体图像的私有内部细节,但只能作为只要图像界面提供客户想要对图像执行的所有操作。

通常在某些时候,界面不能希望为整个世界提供可想象的每个功能,所以当遇到性能关键问题而同时需要满足广泛的需求时,这些界面经常会泄漏它们的混凝土细节。抽象图像仍然可以通过一个pixels()方法提供一个指向其底层像素的指针,这个方法在很大程度上破坏了接口编码的许多目的,但在大多数性能关键领域通常都是必需的。

一般来说,很多最高效的代码通常必须针对某些级别的非常具体的细节进行编写,例如专门为单精度浮点编写的代码,专门为32位RGBA图像编写的代码,代码这是专门为GPU编写的,专门针对AVX-512,特别是针对移动硬件等。所以这是一个基本的障碍,至少对于我们迄今为止所使用的工具,我们无法将其全部抽象出来,只是将代码编码到一个没有暗示的接口罚款。

当然,如果我们可以编写代码,忘记所有这些具体细节,例如我们是在处理32位SPFP还是64位DPFP,我们是不是正在编写着色器,我们的生活就会变得如此简单有限的移动设备或高端桌面,并且它们都是最有竞争力的代码。但我们离这个阶段还很远。我们目前的工具仍然经常要求我们针对具体细节编写我们的性能关键代码。

最后,这是一个粒度问题。当然,如果我们必须逐个像素地处理事物,那么任何试图抽象出像素的具体细节的尝试都可能导致性能损失。但是,如果我们在图像层面上表达事物,例如“alpha将这两个图像混合在一起”,那么即使存在虚拟调度开销等等,这也可能是微不足道的成本。因此,当我们向更高级别的代码努力时,编码到接口的任何暗示性能损失都会减少到变得完全无关紧要的程度。但总是需要低级代码,它像逐个像素一样处理事物,每帧循环数百万次,并且编码到接口的代价可以带有漂亮的效果如果仅仅是因为它隐藏了写出最有效实施所必需的具体细节,那么将会受到重大的惩罚。