![]() |
1
3
我认为您看到了不同之处,但这只是函数调用开销。在这两种情况下,分支预测失误、内存访问和trig函数都是相同的。与这些相比,这没什么大不了的,尽管函数指针的情况在我尝试的时候确实快了一点。 如果这是您的大型程序的代表,这是一个很好的证明,这种类型的微优化有时只是沧海一粟,最糟糕的是徒劳无功。但撇开这一点不谈,为了进行更清晰的测试,函数应该执行一些更简单的操作,这对于每个函数都是不同的:
等等,类似于虚拟函数。 (每个函数都应该做一些不同的事情,这样它们就不会被省略,最终得到相同的地址;这将使分支预测工作不切实际。) 有了这些变化,结果有点不同。每种情况下最好4次。(不是很科学,但是对于较大的运行次数来说,这些数字大体上是相似的。)所有的时间都是循环的,在我的笔记本电脑上运行。代码是用vc++编译的(只改变了时间),但gcc以同样的方式实现虚拟函数调用,因此即使使用不同的OS/x86 CPU/编译器,相对时间也应该大致相似。 函数指针:2052770 虚拟:3598039 这种差别似乎有点过分!当然,这两位代码在内存访问行为方面并不完全相同。第二张桌子应该有一张4a*s的桌子,用来填充底座,而不是为每个条目新建一张新的桌子。然后,当获取要跳转的指针时,这两个示例将具有类似的行为(1个缓存未命中/n项)。例如:
在这种情况下,仍然使用简化的函数: 虚拟(此处建议):2487699 所以有20%是最好的。足够接近吗? 所以,也许你的同事至少考虑到这一点是正确的,但我怀疑在任何现实的程序中,呼叫开销都不足以成为一个瓶颈,不值得跳过去。 |
![]() |
2
8
在这两种情况下,都是间接调用函数。一种是通过函数指针表,另一种是通过编译器的函数指针数组(vtable)。毫不奇怪,两个相似的操作会给您带来相似的计时结果。 |
![]() |
3
4
虚拟函数可能比常规函数慢,但这是由于诸如inline之类的原因造成的。如果您通过函数表调用一个函数,那么这些函数也不能被内联,并且查找时间几乎相同。通过自己的查找表进行查找当然与通过编译器的查找表进行查找相同。
|
![]() |
4
3
现在,在大多数系统中,内存访问是主要的瓶颈,而不是CPU。在许多情况下,虚函数和非虚函数之间几乎没有显著的区别——它们通常只代表执行时间的一小部分。(不好意思,我没有报告数据来支持这一点,只是实证数据。) 如果你想获得最好的性能,如果你研究如何并行计算以利用多个核心/处理单元,而不是担心虚函数和非虚函数的微观细节,你将得到更多的回报。 |
![]() |
5
3
许多人之所以养成这样的习惯,仅仅是因为他们被认为“更快”。 都是相对的。 如果我要从家里开100英里的车,我必须先绕着街区开车。我可以绕街区向右或向左行驶。其中之一就是“更快”。但这有关系吗?当然不是。 在这种情况下,您调用的函数依次调用数学函数。 如果您在IDE或GDB下暂停程序,我怀疑您会发现,几乎每次暂停程序时,它都会出现在那些数学库例程中(或者应该出现!),并且取消引用一个额外的指向那里的指针(假设它不会破坏缓存)应该在噪声中丢失。
添加:以下是最喜爱的视频:
Harry Porter's relay computer
. 当这件事费劲地敲打着加上数字和步进它的程序计数器时,我发现记住这是所有计算机都在做的,只是在不同的时间和复杂程度上。在你的例子中,考虑一个算法
|
![]() |
6
0
最后,函数指针方法被证明是最快的方法。这是我从一开始就预料到的。 |
![]() |
giantjenga · 优化整数向量到二进制向量的转换 6 月前 |
![]() |
Daniel Lobo · 使用约束进行优化 7 月前 |
![]() |
Imyaf · 在什么条件下,在组装时对“if”和“if-else”进行比较? 10 月前 |
![]() |
Sergio · python中大量数字的乘法 12 月前 |
![]() |
Sergey Dev · 临时表与表变量 1 年前 |
![]() |
John · 减少C中的内存消耗++ 1 年前 |