在c ++中,什么是估计内联函数的计算时间优势的良好启发式方法,特别是当函数被非常频繁地调用并且占该程序执行时间的≥10%时(例如,评估函数的蛮力或随机优化过程)。即使内联可能最终超出我的控制范围,我仍然很好奇。
答案 0 :(得分:6)
没有一般答案。这取决于硬件,数量和 它的参数类型,以及函数中的内容。多久一次 它被称为,在哪里。例如,在Sparc上,参数(和 返回值)在寄存器中传递,每个函数获得16个新函数 寄存器:如果函数足够复杂,那些新寄存器可能会 避免溢出,如果函数内联,将发生 非内联版本可能比内联版本更快。在英特尔, 这是寄存器差,并在寄存器中传递参数,只是 对于同一程序中的相同功能,反之亦然。更多 通常,内联可能会增加程序大小,减少位置。要么 对于非常简单的功能,它可能会减少程序大小;但那又一次 取决于架构。唯一可能的方法就是尝试 两者,衡量时间。即便如此,你也只会知道 特定程序,在特定的硬件上。
答案 1 :(得分:1)
某些体系结构上的函数调用和返回只需要一条指令(尽管它们通常不是类似RISC的单周期指令。)通常,您可以将它与正文表示的循环数进行比较。功能。一个简单的属性访问可能只是一个指令,因此将它放入一个非内联函数将使执行它的指令数量增加三倍 - 显然是内联的一个很好的选择。另一方面,格式化字符串以进行打印的函数可能代表数百条指令,因此另外两条指令根本不会产生任何差异。
答案 2 :(得分:1)
如果您的瓶颈在递归函数中,并且假设递归级别不是最小的(即平均递归不仅仅是几个级别),那么最好在函数中使用算法而不是< EM>内联
如果可能的话,尝试将递归转换为循环或尾递归(可以由编译器隐式转换为循环),或者尝试确定函数中的成本在哪里正在度过。尽量减少内部操作的影响(也许你是动态分配可能具有自动存储持续时间的内存,或者你可以将一个常见操作考虑在包装器中的函数外部执行,并作为额外的参数传入。 ..)
*在递归的意见之后编辑,而不是迭代*
如果编译器可以访问函数的定义,它将在大多数情况下为您做出正确的决定。如果它无法访问定义,只需移动代码以便它确实可以看到它。也许使函数成为static
函数,以提供额外的提示,使其不会在其他任何地方使用,或者甚至将其标记为inline
(知道这不会强制内联),但避免使用特殊的强制内联的属性,因为编译器可能比任何可以在不查看代码的情况下生成的简单启发式方法做得更好。
答案 3 :(得分:1)
所有内联都会保存您的功能,因此只有考虑,如果该功能几乎不执行任何操作。 当然,如果函数本身包含函数调用,则可能不值得考虑。
即使该函数做得很少,也必须调用它以至于它在很大程度上拥有程序计数器的时间,然后才会显着加快函数的加速。
答案 4 :(得分:0)
这里的行为有点依赖于编译器。使用递归函数,显然内联行为在理论上可以是无限的。 'inline'关键字只是对编译器的一个提示,如果它不能对它做任何事情,它可以选择忽略它。一些编译器会将递归函数内联到一定深度。
至于“这会加快多少速度” - 遗憾的是我们无法提供任何类型的答案,因为“它取决于” - 函数做了多少工作与函数调用机制的开销本身。你为什么不设置测试并看看?
答案 5 :(得分:0)
我们在编写计算密集型C ++ 20多年的经验是,内联不是银弹。您确实需要对代码进行概要分析,以确定内联是否会提高性能。对于我们来说,除了低水平的2D和3D点和矢量操作之外,内联是浪费时间。你想要制定一个更好的算法比试图微观时钟滴答更好。