C++ 紧环中虚函数的代价

C++ 紧环中虚函数的代价,c++,optimization,virtual-functions,C++,Optimization,Virtual Functions,我的游戏对象有一个虚拟函数Update()。有很多游戏对象(目前略多于7000个),循环调用会更新所有对象(除其他外)。我的同事建议我们应该完全删除虚拟函数。正如您所想象的,这将需要大量重构 我已经看到了,但在我的例子中,分析意味着我必须更改很多代码。所以,在我考虑开始之前,我想在这里征求一下关于重构在这种情况下是否值得的意见 请注意,我已经分析了循环的其他部分,并一直在尝试优化耗时最长的部分。我怀疑在这种情况下,虚拟函数调用是我不应该担心的事情,但是在我分析之前我不能确定,在我更改代码之前我也

我的游戏对象有一个虚拟函数Update()。有很多游戏对象(目前略多于7000个),循环调用会更新所有对象(除其他外)。我的同事建议我们应该完全删除虚拟函数。正如您所想象的,这将需要大量重构

我已经看到了,但在我的例子中,分析意味着我必须更改很多代码。所以,在我考虑开始之前,我想在这里征求一下关于重构在这种情况下是否值得的意见

请注意,我已经分析了循环的其他部分,并一直在尝试优化耗时最长的部分。我怀疑在这种情况下,虚拟函数调用是我不应该担心的事情,但是在我分析之前我不能确定,在我更改代码之前我也不能分析(这是非常多的)。还请注意,一些更新函数非常小,而另一些更新函数则更大、更复杂


编辑:有多个答案可以提供很好的洞察力,因此任何人在将来偶然发现这个问题时,都可以查看所有答案,而不仅仅是选定的答案。

虚拟函数调用只会添加一个间接过程和一个难以预测的跳跃。这意味着,通常情况下,每个虚拟函数需要一个管道刷新或大约20个周期。其中7000个周期约为140000个周期,与您的平均更新功能相比应该可以忽略不计。如果不是,假设你的大多数更新函数只是空的,你可以考虑将可更新的对象放在一个单独的列表中。p> 删除虚拟功能只会导致你们中的一个人用一个相同但自我实现的系统来替换它。这正是虚拟函数有意义的地方


根据参考,140000次循环约为50微秒。这是假设一个P4有一个巨大的管道,并且总是有一个完整的管道刷新(这是你通常不会得到的)。

如果你不能分析,看看汇编代码,了解一下查找的成本到底有多高。这可能是一个简单的间接跳跃,成本几乎为零

如果需要重构,这里有一个建议:创建大量“UpdateXxx”类,它们知道如何调用新的非虚拟
update()
方法。收集数组中的数据,然后对其调用
update()

但我的猜测是,你不会节省太多,尤其是只有7K的对象


关于评测的注意事项:如果您不能使用评测器(让我想知道为什么不能),那么将调用计时到
update()
,并记录耗时超过100毫秒的调用。计时并不昂贵,它允许您快速确定哪些呼叫最昂贵。

您可以在此处找到虚拟、内联和直接呼叫的另一个测试 [在此处输入链接说明][1]

尽管它与您使用的代码不同,也可能不是同一个编译器,但这里有一些参考数据来自一个相当古老的基准测试(Joe Orost的bench++):

测试名称:F000005类名:样式
CPU时间:7.70纳秒正负0.385
墙壁/CPU:1.00比率。迭代次数:1677721600
测试说明:
使用10路if/else if语句测试全局变量的时间
将此测试与F000006进行比较
测试名称:F000006类名:样式
CPU时间:2.00纳秒正负0.0999
墙壁/CPU:1.00比率。迭代次数:1677721600
测试说明:
使用10路开关语句测试全局变量的时间
将此测试与F000005进行比较
测试名称:F000007类名:样式
CPU时间:3.41纳秒正负0.171纳秒
墙壁/CPU:1.00比率。迭代次数:1677721600
测试说明:
使用10路稀疏开关语句测试全局变量的时间
将此测试与F000005和F000006进行比较
测试名称:F000008类名:样式
CPU时间:2.20纳秒正负0.110
墙壁/CPU:1.00比率。迭代次数:1677721600
测试说明:
使用10路虚拟函数类测试全局函数的时间
将此测试与F000006进行比较
这个特殊的结果来自于使用64位版本的VC++9.0(VS 2008)进行编译,但它与我在最近的其他编译器中看到的非常相似。底线是,虚拟函数比大多数明显的替代函数都要快,并且非常接近于唯一一个击败它的函数的速度(事实上,两者相等在测量的误差范围内)。然而,这取决于涉及的值是否密集——正如您在F00007中看到的,如果值是稀疏的,switch语句生成的代码比虚拟函数调用慢


一句话:虚拟函数调用可能是错误的。重构后的代码可能很容易运行得较慢,即使是最好的情况,也可能无法引起足够的注意或关注。

从您提供的信息来看,重构可能很困难或不可能。原因是有几种不同类型的Update()函数。通过重构,您将得到的只是虚拟函数调用将被switch-case或if语句所取代,这些语句在性能上没有任何改进。有人怎么敢问优化问题呢!:P像往常一样,在这些类型的问题上,-1,但不解释原因。无论如何,感谢所有回复的人。我所需要的是另一种意见,我得到了。我不知道为什么有些人执意要把所有的东西都埋在这里,甚至还有“优化”这个词。我正在开发自己的游戏引擎,目前在顶级机器上的运行速度约为10fps。不知道去哪里看,但我在afr