- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
这个问题主要与我遇到的大型代码维护和可重用性问题有关。我有几个类有这样的方法:
void MyClassX::Draw(){
///Some large chunk of code#1 here
///Another large chunk of code#2 goes here
///Another large chunk of code#3 goes here
}
void MyClassY::Draw(){
///Some large chunk of code#1 here
///Another large chunk of code#2 goes here
}
该方法的不同之处在于,其中一些代码块在不同的类中是可选的。现在,这听起来可能很愚蠢,但因为该方法执行了一些性能关键的实时处理(3D 渲染)。我不对这些代码块使用函数,也不想将它们与那些代码块一起包装,因为我试图减少一般的函数调用数量。我想要的是在某个 block 中定义这些函数(例如使用 #define),然后在 void Draw()
内的适当位置声明这些函数而不是整个代码块。我不想为它使用预处理器,因为很难编辑这样的代码(没有适当的错误提示或调试)。我认为的另一种选择是内联函数。但是因为编译器不保证内联我不确定这种方式是否有效。还有其他技巧吗?也许通过 C++ 模板的使用?我可以强制某些函数体在调用方方法内部衰减吗?
附言出于性能考虑,我也不对这些类使用继承,因为它基本上也可以通过将所有这些 block 定义为基类中的函数来解决该问题。同样在 void Draw()
中,我尝试将条件分支减少到最低限度。
最佳答案
有一些方法可以在某些编译器上强制内联函数,例如 MSVC 上的 __forceinline
或 GCC 上的 __attribute__((always_inline))
。它非常特定于编译器,但您可以通过一些警告来保证它。在那里,我建议检查您的编译器文档,并习惯于在某个广泛的层面上分析反汇编(足以识别函数调用,例如,这相当容易,因为您可以使用调试器跟踪它并注意到它何时发生分支)。
也就是说,我真的认为您可能看错了。我可能是错的,也许你有我以前没有遇到过的非常特殊的需求,但我在一个性能关键领域,除了正确性之外,效率通常与产品的感知质量成正比(我' m 也在 3D 中,包括路径跟踪)。
我习惯于使用手头的分析器,并且学会了对优化器持保留态度。有些事情优化器和标准库做得不好,我习惯于做一些事情,比如滚动我自己的内存分配器,获得可观的 yield 。
但在我的无数分析 session 中,我从未遇到过编译器在函数调用开销方面做得不好的情况。我已经看到优化器出现问题并且在指令选择或寄存器分配方面做得很差,其中以某种实际上不应该帮助的方式重写代码确实有助于发出更高效的汇编。这包括将一些大块代码转换为更多函数,您认为这不会提高性能,但会在这两个方面(寄存器分配和指令选择)帮助编译器。
我在优化中发现的一个更有帮助的事情是优化器可能很棒,但它们不了解在运行时将接收什么样的用户输入。这是常见案例执行的一个关键方面,只有了解产品设计的人才能预见到。所以我发现的一件事是,将罕见的代码分支放入单独的、未内联的函数中,这样逻辑就不会全部内联在一个巨大的 blob 中,实际上在某种程度上有所帮助(没有调查所有这些的反汇编情况下,只是注意到时间上的改进)。我认为这只是在某种程度上帮助编译器不要将您的所有代码视为一种公平的竞争环境,帮助它更有选择地/局部地进行优化,因为例如只有这么多寄存器,并且将所有内容都放在一个巨大的函数可能会使优化器混淆哪个部分需要更多关注。
也就是说,我发现在分析和优化过程中使用更集中的代码通常很有帮助。这并不是因为在大型函数中使用更集中的代码实际上会加快速度,而是因为当您试图挤出微观层面的效率时,使用结构化程度较低的东西会更容易。在你微调之后强加更多的结构比在你通过那些详尽的分析 session 之前试图解开它更容易,所以有时以这种方式编写代码并牺牲一些整洁和结构来获得大的代码会很有帮助代码块。但好处更多的是,在对代码进行概要分析并事后获得效率知识以帮助组织代码后,可以轻松更改此类代码;我从未真正见过这样的代码实际上让事情变得更快。
所以我真的认为你最好不要专注于内联那么多,而将其更多地留给优化器。即使在最小的微观效率水平下,通常也有更好的东西可以优化并获得更明显的 yield 。
关于c++ - 在调用方方法中衰减多个函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30376653/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!