对接口进行编码而不是实现是否会影响性能?

时间:2022-12-23 16:54:02

In day to day programs I wouldn't even bother thinking about the possible performance hit for coding against interfaces rather than implementations. The advantages largely outweigh the cost. So please no generic advice on good OOP.

在日常程序中,我甚至不会考虑针对接口而不是实现编码的可能性能损失。优势大大超过了成本。所以请不要提供关于良好OOP的通用建议。

Nevertheless in this post, the designer of the XNA (game) platform gives as his main argument to not have designed his framework's core classes against an interface that it would imply a performance hit. Seeing it is in the context of a game development where every fps possibly counts, I think it is a valid question to ask yourself.

尽管如此,在这篇文章中,XNA(游戏)平台的设计者给出了他的主要论点,即没有设计他的框架的核心类来对抗界面,这意味着性能受到打击。看到它是在游戏开发的背景下,每个fps可能都很重要,我认为这是一个有效的问题要问自己。

Does anybody have any stats on that? I don't see a good way to test/measure this as don't know what implications I should bear in mind with such a game (graphics) object.

有人有任何统计数据吗?我没有看到测试/测量这个的好方法,因为我不知道这个游戏(图形)对象应该记住什么含义。

8 个解决方案

#1


Interfaces generally imply a few hits to performance (this however may change depending on the language/runtime used):

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

  1. Interface methods are usually implemented via a virtual call by the compiler. As another user points out, these can not be inlined by the compiler so you lose that potential gain. Additionally, they add a few instructions (jumps and memory access) at a minimum to get the proper PC in the code segment.
  2. 接口方法通常通过编译器的虚拟调用来实现。正如另一位用户指出的那样,编译器无法对这些内容进行内联,因此您将失去这种潜在的收益。此外,它们至少添加了一些指令(跳转和内存访问),以便在代码段中获得正确的PC。

  3. Interfaces, in a number of languages, also imply a graph and require a DAG (directed acyclic graph) to properly manage memory. In various languages/runtimes you can actually get a memory 'leak' in the managed environment by having a cyclic graph. This imposes great stress (obviously) on the garbage collector/memory in the system. Watch out for cyclic graphs!
  4. 许多语言的接口也意味着图形并且需要DAG(有向非循环图)来正确管理存储器。在各种语言/运行时中,通过使用循环图,您实际上可以在托管环境中获得内存“泄漏”。这显然给系统中的垃圾收集器/内存带来了很大的压力。注意循环图!

  5. Some languages use a COM style interface as their underlying interface, automatically calling AddRef/Release whenever the interface is assigned to a local, or passed by value to a function (used for life cycle management). These AddRef/Release calls can add up and be quite costly. Some languages have accounted for this and may allow you to pass an interface as 'const' which will not generate the AddRef/Release pair automatically cutting down on these calls.
  6. 某些语言使用COM样式接口作为其底层接口,只要将接口分配给本地,或者通过值传递给函数(用于生命周期管理),就会自动调用AddRef / Release。这些AddRef / Release调用可能会增加并且成本很高。有些语言已经解释了这一点,并且可能允许您将接口作为“const”传递,这将不会生成自动减少这些调用的AddRef / Release对。

Here is a small example of a cyclic graph where 2 interfaces reference each other and neither will automatically be collected as their refcounts will always be greater than 1.

下面是一个循环图的一个小例子,其中2个接口相互引用,并且两者都不会被自动收集,因为它们的refcounts总是大于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.
}

#2


Coding to an interface is always going to be easier, simply because interfaces, if done right, are much simpler. Its palpably easier to write a correct program using an interface.

编码到接口总是更容易,因为接口,如果做得好,则更简单。使用界面编写正确的程序显然更容易。

And as the old maxim goes, its easier to make a correct program run fast than to make a fast program run correctly.

正如旧格言所说的那样,更快地制作正确的程序比使快速程序正确运行更容易。

So program to the interface, get everything working and then do some profiling to help you meet whatever performance requirements you may have.

所以编程到界面,让一切工作,然后做一些分析,以帮助您满足您可能有的任何性能要求。

#3


What Things Cost in Managed Code

管理代码的成本是多少

"There does not appear to be a significant difference in the raw cost of a static call, instance call, virtual call, or interface call."

“静态呼叫,实例呼叫,虚拟呼叫或接口呼叫的原始成本似乎没有显着差异。”

It depends on how much of your code gets inlined or not at compile time, which can increase performance ~5x.

这取决于您的代码在编译时是否有多少内联,这可以将性能提高~5倍。

It also takes longer to code to interfaces, because you have to code the contract(interface) and then the concrete implementation.

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

But doing things the right way always takes longer.

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

#4


First I'd say that the common conception is that programmers time is usually more important, and working against implementation will probably force much more work when the implementation changes.

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

Second with proper compiler/Jit I would assume that working with interface takes a ridiculously small amount of extra time compared to working against the implementation itself. Moreover, techniques like templates can remove the interface code from running.

第二,使用正确的编译器/ Jit我会假设使用接口与实现本身相比,需要花费极少量的额外时间。此外,模板等技术可以删除界面代码。

Third to quote Knuth : "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."
So I'd suggest coding well first, and only if you are sure that there is a problem with the Interface, only then I would consider changing.

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

Also I would assume that if this performance hit was true, most games wouldn't have used an OOP approach with C++, but this is not the case, this Article elaborates a bit about it.

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

It's hard to talk about tests in a general form, naturally a bad program may spend a lot of time on bad interfaces, but I doubt if this is true for all programs, so you really should look at each particular program.

很难以一般形式谈论测试,自然坏程序可能会花很多时间在坏接口上,但我怀疑这对所有程序是否都是如此,所以你真的应该看看每个特定的程序。

#5


I think object lifetime and the number of instances you're creating will provide a coarse-grain answer.

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

If you're talking about something which will have thousands of instances, with short lifetimes, I would guess that's probably better done with a struct rather than a class, let alone a class implementing an interface.

如果你正在谈论会有数千个实例,生命周期很短的事情,我猜想用一个结构而不是一个类可能会更好,更不用说一个实现接口的类了。

For something more component-like, with low numbers of instances and moderate-to-long lifetime, I can't imagine it's going to make much difference.

对于更像组件,具有少量实例和中等到长寿命的东西,我无法想象它会产生很大的不同。

#6


IMO yes, but for a fundamental design reason far more subtle and complex than virtual dispatch or COM-like interface queries or object metadata required for runtime type information or anything like that. There is overhead associated with all of that but it depends a lot on the language and compiler(s) used, and also depends on whether the optimizer can eliminate such overhead at compile-time or link-time. Yet in my opinion there's a broader conceptual reason why coding to an interface implies (not guarantees) a performance hit:

IMO是的,但是出于基本的设计原因,比运行类型信息或类似的虚拟调度或类似COM的接口查询或对象元数据更加微妙和复杂。所有这些都有相关的开销,但它在很大程度上取决于所使用的语言和编译器,还取决于优化器是否可以在编译时或链接时消除这种开销。然而在我看来,有一个更广泛的概念性原因,为什么编码到接口意味着(不保证)性能损失:

Coding to an interface implies that there is a barrier between you and the concrete data/memory you want to access and transform.

编码到接口意味着您与要访问和转换的具体数据/内存之间存在障碍。

This is the primary reason I see. As a very simple example, let's say you have an abstract image interface. It fully abstracts away its concrete details like its pixel format. The problem here is that often the most efficient image operations need those concrete details. We can't implement our custom image filter with efficient SIMD instructions, for example, if we had to getPixel one at a time and setPixel one at a time and while oblivious to the underlying pixel format.

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

Of course the abstract image could try to provide all these operations, and those operations could be implemented very efficiently since they have access to the private, internal details of the concrete image which implements that interface, but that only holds up as long as the image interface provides everything the client would ever want to do with an image.

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

Often at some point an interface cannot hope to provide every function imaginable to the entire world, and so such interfaces, when faced with performance-critical concerns while simultaneously needing to fulfill a wide range of needs, will often leak their concrete details. The abstract image might still provide, say, a pointer to its underlying pixels through a pixels() method which largely defeats a lot of the purpose of coding to an interface, but often becomes a necessity in the most performance-critical areas.

通常在某些时候,接口不能希望提供整个世界可以想象的所有功能,因此当面对性能关键问题同时需要满足各种需求时,这样的接口通常会泄漏其具体细节。例如,抽象图像可能仍然通过像素()方法提供指向其底层像素的指针,这种方法在很大程度上破坏了编码到接口的许多目的,但在大多数性能关键区域中经常成为必需品。

Just in general a lot of the most efficient code often has to be written against very concrete details at some level, like code written specifically for single-precision floating-point, code written specifically for 32-bit RGBA images, code written specifically for GPU, specifically for AVX-512, specifically for mobile hardware, etc. So there's a fundamental barrier, at least with the tools we have so far, where we cannot abstract that all away and just code to an interface without an implied penalty.

总的来说,许多最有效的代码通常必须在某种程度上针对非常具体的细节编写,例如专门为单精度浮点编写的代码,专门为32位RGBA映像编写的代码,专门为GPU编写的代码特别是对于AVX-512,特别是对于移动硬件等。所以有一个基本的障碍,至少对于我们到目前为止的工具,我们无法抽象出所有的东西,只是编码到接口而没有隐含的惩罚。

Of course our lives would become so much easier if we could just write code, oblivious to all such concrete details like whether we're dealing with 32-bit SPFP or 64-bit DPFP, whether we're writing shaders on a limited mobile device or a high-end desktop, and have all of it be the most competitively efficient code out there. But we're far from that stage. Our current tools still often require us to write our performance-critical code against concrete details.

当然,如果我们只能编写代码,我们的生活会变得如此简单,无论我们是处理32位SPFP还是64位DPFP,无论我们是否在有限的移动设备上编写着色器,都会忘记所有这些具体细节或者是高端桌面,并且所有这些都是最具竞争力的高效代码。但我们离那个阶段还很远。我们当前的工具仍然经常要求我们根据具体细节编写性能关键代码。

And lastly this is kind of an issue of granularity. Naturally if we have to work with things on a pixel-by-pixel basis, then any attempts to abstract away concrete details of a pixel could lead to a major performance penalty. But if we're expressing things at the image level like, "alpha blend these two images together", that could be a very negligible cost even if there's virtual dispatch overhead and so forth. So as we work towards higher-level code, often any implied performance penalty of coding to an interface diminishes to a point of becoming completely trivial. But there's always that need for the low-level code which does do things like process things on a pixel-by-pixel basis, looping through millions of them many times per frame, and there the cost of coding to an interface can carry a pretty substantial penalty, if only because it's hiding the concrete details necessary to write the most efficient implementation.

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

#7


In my personal opinion, all the really heavy lifting when it comes to graphics is passed on to the GPU anwyay. These frees up your CPU to do other things like program flow and logic. I am not sure if there is a performance hit when programming to an interface but thinking about the nature of games, they are not something that needs to be extendable. Maybe certain classes but on the whole I wouldn't think that a game needs to programmed with extensibility in mind. So go ahead, code the implementation.

在我个人看来,当涉及到图形时,所有非常繁重的工作都被传递到GPU anwyay。这些可以释放CPU来执行程序流和逻辑等其他操作。我不确定在编程接口时是否有性能损失,但考虑到游戏的性质,它们不是需要可扩展的东西。也许某些课程,但总的来说,我不认为游戏需要考虑到可扩展性。所以继续编写实现代码。

#8


it would imply a performance hit

这意味着性能受到打击

The designer should be able to prove his opinion.

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

#1


Interfaces generally imply a few hits to performance (this however may change depending on the language/runtime used):

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

  1. Interface methods are usually implemented via a virtual call by the compiler. As another user points out, these can not be inlined by the compiler so you lose that potential gain. Additionally, they add a few instructions (jumps and memory access) at a minimum to get the proper PC in the code segment.
  2. 接口方法通常通过编译器的虚拟调用来实现。正如另一位用户指出的那样,编译器无法对这些内容进行内联,因此您将失去这种潜在的收益。此外,它们至少添加了一些指令(跳转和内存访问),以便在代码段中获得正确的PC。

  3. Interfaces, in a number of languages, also imply a graph and require a DAG (directed acyclic graph) to properly manage memory. In various languages/runtimes you can actually get a memory 'leak' in the managed environment by having a cyclic graph. This imposes great stress (obviously) on the garbage collector/memory in the system. Watch out for cyclic graphs!
  4. 许多语言的接口也意味着图形并且需要DAG(有向非循环图)来正确管理存储器。在各种语言/运行时中,通过使用循环图,您实际上可以在托管环境中获得内存“泄漏”。这显然给系统中的垃圾收集器/内存带来了很大的压力。注意循环图!

  5. Some languages use a COM style interface as their underlying interface, automatically calling AddRef/Release whenever the interface is assigned to a local, or passed by value to a function (used for life cycle management). These AddRef/Release calls can add up and be quite costly. Some languages have accounted for this and may allow you to pass an interface as 'const' which will not generate the AddRef/Release pair automatically cutting down on these calls.
  6. 某些语言使用COM样式接口作为其底层接口,只要将接口分配给本地,或者通过值传递给函数(用于生命周期管理),就会自动调用AddRef / Release。这些AddRef / Release调用可能会增加并且成本很高。有些语言已经解释了这一点,并且可能允许您将接口作为“const”传递,这将不会生成自动减少这些调用的AddRef / Release对。

Here is a small example of a cyclic graph where 2 interfaces reference each other and neither will automatically be collected as their refcounts will always be greater than 1.

下面是一个循环图的一个小例子,其中2个接口相互引用,并且两者都不会被自动收集,因为它们的refcounts总是大于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.
}

#2


Coding to an interface is always going to be easier, simply because interfaces, if done right, are much simpler. Its palpably easier to write a correct program using an interface.

编码到接口总是更容易,因为接口,如果做得好,则更简单。使用界面编写正确的程序显然更容易。

And as the old maxim goes, its easier to make a correct program run fast than to make a fast program run correctly.

正如旧格言所说的那样,更快地制作正确的程序比使快速程序正确运行更容易。

So program to the interface, get everything working and then do some profiling to help you meet whatever performance requirements you may have.

所以编程到界面,让一切工作,然后做一些分析,以帮助您满足您可能有的任何性能要求。

#3


What Things Cost in Managed Code

管理代码的成本是多少

"There does not appear to be a significant difference in the raw cost of a static call, instance call, virtual call, or interface call."

“静态呼叫,实例呼叫,虚拟呼叫或接口呼叫的原始成本似乎没有显着差异。”

It depends on how much of your code gets inlined or not at compile time, which can increase performance ~5x.

这取决于您的代码在编译时是否有多少内联,这可以将性能提高~5倍。

It also takes longer to code to interfaces, because you have to code the contract(interface) and then the concrete implementation.

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

But doing things the right way always takes longer.

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

#4


First I'd say that the common conception is that programmers time is usually more important, and working against implementation will probably force much more work when the implementation changes.

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

Second with proper compiler/Jit I would assume that working with interface takes a ridiculously small amount of extra time compared to working against the implementation itself. Moreover, techniques like templates can remove the interface code from running.

第二,使用正确的编译器/ Jit我会假设使用接口与实现本身相比,需要花费极少量的额外时间。此外,模板等技术可以删除界面代码。

Third to quote Knuth : "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."
So I'd suggest coding well first, and only if you are sure that there is a problem with the Interface, only then I would consider changing.

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

Also I would assume that if this performance hit was true, most games wouldn't have used an OOP approach with C++, but this is not the case, this Article elaborates a bit about it.

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

It's hard to talk about tests in a general form, naturally a bad program may spend a lot of time on bad interfaces, but I doubt if this is true for all programs, so you really should look at each particular program.

很难以一般形式谈论测试,自然坏程序可能会花很多时间在坏接口上,但我怀疑这对所有程序是否都是如此,所以你真的应该看看每个特定的程序。

#5


I think object lifetime and the number of instances you're creating will provide a coarse-grain answer.

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

If you're talking about something which will have thousands of instances, with short lifetimes, I would guess that's probably better done with a struct rather than a class, let alone a class implementing an interface.

如果你正在谈论会有数千个实例,生命周期很短的事情,我猜想用一个结构而不是一个类可能会更好,更不用说一个实现接口的类了。

For something more component-like, with low numbers of instances and moderate-to-long lifetime, I can't imagine it's going to make much difference.

对于更像组件,具有少量实例和中等到长寿命的东西,我无法想象它会产生很大的不同。

#6


IMO yes, but for a fundamental design reason far more subtle and complex than virtual dispatch or COM-like interface queries or object metadata required for runtime type information or anything like that. There is overhead associated with all of that but it depends a lot on the language and compiler(s) used, and also depends on whether the optimizer can eliminate such overhead at compile-time or link-time. Yet in my opinion there's a broader conceptual reason why coding to an interface implies (not guarantees) a performance hit:

IMO是的,但是出于基本的设计原因,比运行类型信息或类似的虚拟调度或类似COM的接口查询或对象元数据更加微妙和复杂。所有这些都有相关的开销,但它在很大程度上取决于所使用的语言和编译器,还取决于优化器是否可以在编译时或链接时消除这种开销。然而在我看来,有一个更广泛的概念性原因,为什么编码到接口意味着(不保证)性能损失:

Coding to an interface implies that there is a barrier between you and the concrete data/memory you want to access and transform.

编码到接口意味着您与要访问和转换的具体数据/内存之间存在障碍。

This is the primary reason I see. As a very simple example, let's say you have an abstract image interface. It fully abstracts away its concrete details like its pixel format. The problem here is that often the most efficient image operations need those concrete details. We can't implement our custom image filter with efficient SIMD instructions, for example, if we had to getPixel one at a time and setPixel one at a time and while oblivious to the underlying pixel format.

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

Of course the abstract image could try to provide all these operations, and those operations could be implemented very efficiently since they have access to the private, internal details of the concrete image which implements that interface, but that only holds up as long as the image interface provides everything the client would ever want to do with an image.

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

Often at some point an interface cannot hope to provide every function imaginable to the entire world, and so such interfaces, when faced with performance-critical concerns while simultaneously needing to fulfill a wide range of needs, will often leak their concrete details. The abstract image might still provide, say, a pointer to its underlying pixels through a pixels() method which largely defeats a lot of the purpose of coding to an interface, but often becomes a necessity in the most performance-critical areas.

通常在某些时候,接口不能希望提供整个世界可以想象的所有功能,因此当面对性能关键问题同时需要满足各种需求时,这样的接口通常会泄漏其具体细节。例如,抽象图像可能仍然通过像素()方法提供指向其底层像素的指针,这种方法在很大程度上破坏了编码到接口的许多目的,但在大多数性能关键区域中经常成为必需品。

Just in general a lot of the most efficient code often has to be written against very concrete details at some level, like code written specifically for single-precision floating-point, code written specifically for 32-bit RGBA images, code written specifically for GPU, specifically for AVX-512, specifically for mobile hardware, etc. So there's a fundamental barrier, at least with the tools we have so far, where we cannot abstract that all away and just code to an interface without an implied penalty.

总的来说,许多最有效的代码通常必须在某种程度上针对非常具体的细节编写,例如专门为单精度浮点编写的代码,专门为32位RGBA映像编写的代码,专门为GPU编写的代码特别是对于AVX-512,特别是对于移动硬件等。所以有一个基本的障碍,至少对于我们到目前为止的工具,我们无法抽象出所有的东西,只是编码到接口而没有隐含的惩罚。

Of course our lives would become so much easier if we could just write code, oblivious to all such concrete details like whether we're dealing with 32-bit SPFP or 64-bit DPFP, whether we're writing shaders on a limited mobile device or a high-end desktop, and have all of it be the most competitively efficient code out there. But we're far from that stage. Our current tools still often require us to write our performance-critical code against concrete details.

当然,如果我们只能编写代码,我们的生活会变得如此简单,无论我们是处理32位SPFP还是64位DPFP,无论我们是否在有限的移动设备上编写着色器,都会忘记所有这些具体细节或者是高端桌面,并且所有这些都是最具竞争力的高效代码。但我们离那个阶段还很远。我们当前的工具仍然经常要求我们根据具体细节编写性能关键代码。

And lastly this is kind of an issue of granularity. Naturally if we have to work with things on a pixel-by-pixel basis, then any attempts to abstract away concrete details of a pixel could lead to a major performance penalty. But if we're expressing things at the image level like, "alpha blend these two images together", that could be a very negligible cost even if there's virtual dispatch overhead and so forth. So as we work towards higher-level code, often any implied performance penalty of coding to an interface diminishes to a point of becoming completely trivial. But there's always that need for the low-level code which does do things like process things on a pixel-by-pixel basis, looping through millions of them many times per frame, and there the cost of coding to an interface can carry a pretty substantial penalty, if only because it's hiding the concrete details necessary to write the most efficient implementation.

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

#7


In my personal opinion, all the really heavy lifting when it comes to graphics is passed on to the GPU anwyay. These frees up your CPU to do other things like program flow and logic. I am not sure if there is a performance hit when programming to an interface but thinking about the nature of games, they are not something that needs to be extendable. Maybe certain classes but on the whole I wouldn't think that a game needs to programmed with extensibility in mind. So go ahead, code the implementation.

在我个人看来,当涉及到图形时,所有非常繁重的工作都被传递到GPU anwyay。这些可以释放CPU来执行程序流和逻辑等其他操作。我不确定在编程接口时是否有性能损失,但考虑到游戏的性质,它们不是需要可扩展的东西。也许某些课程,但总的来说,我不认为游戏需要考虑到可扩展性。所以继续编写实现代码。

#8


it would imply a performance hit

这意味着性能受到打击

The designer should be able to prove his opinion.

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