类似的问题,但不太具体: Performance issue for vector::size() in a loop
假设我们的成员函数如下:
void Object::DoStuff() {
for( int k = 0; k < (int)this->m_Array.size(); k++ )
{
this->SomeNotConstFunction();
this->ConstFunction();
double x = SomeExternalFunction(i);
}
}
1)我愿意相信,如果仅调用“SomeExternalFunction”,编译器将优化而不是冗余地调用m_Array上的size()......是这种情况吗?
2)你几乎肯定不会通过
来提高速度 int N = m_Array.size()
for( int k = 0; k < N; k++ ) { ... }
如果你正在调用一些非const的成员函数?
编辑不确定这些关于微优化的低评和讽刺评论的来源,也许我可以澄清一下:
首先,不是要优化本身,而是要了解编译器将会修复的内容。通常我使用size()函数,但我现在问,因为这里数组可能有数百万个数据点。
其次,情况是“SomeNotConstFunction”可能极有可能改变数组的大小,或者它的能力可能取决于其他一些被切换的变量。所以,我问的是编译器会在什么时候失败,以及当数组真正可能更改时size()的时间成本究竟是多少,尽管人为已知的原因它不会?
第三,循环中的操作非常简单,只有数百万,但它们是令人尴尬的并行。我希望通过外部放置值可以让编译器矢量化一些工作。
答案 0 :(得分:9)
不要养成这样做的习惯。
您在(2)中进行优化的情况是:
很少而且很远。
如果只是后两点,我只是建议你担心一些不重要的事情。然而,第一点是真正的杀手:你不想要养成给自己犯错的机会的习惯。加速缓慢,正确的代码比调试快速,错误的代码要容易得多。
现在,那说,我会尝试回答你的问题。函数SomeNotConstFunction
和SomeConstFunction
的定义(推测)在同一翻译单元中。因此,如果这些函数确实不修改向量,编译器就可以解决它,它只会“调用”size
一次。
但是,编译器无法访问SomeExternalFunction
的定义,因此必须假设每次调用该函数都有可能修改向量。循环中存在该函数可确保每次都调用“size”。
然而,我把“被叫”放在引号中,因为它是如此微不足道的功能,它几乎肯定会被内联。此外,该功能非常便宜 - 两次内存查找(几乎都保证是缓存命中),或者是减法和右移,或者甚至是可以执行这两种操作的专用单个指令。
即使SomeExternalFunction
完全没有做任何事情,很可能每次“调用”size
仍然只是循环运行时间的一小部分甚至可以忽略不计。
编辑:响应编辑......
what exactly is the time cost incurred by size() when the array really might change
您在计算两个不同版本的代码时所看到的时间差异。如果您正在进行非常低级别的优化,那么您无法通过“纯粹的理由”获得答案 - 您必须凭经验测试结果。
如果你真的在做这样的低级优化(并且你可以保证向量不会调整大小),你应该更担心的是编译器不知道数组的基指针是不变的而不是不知道大小是不变的。
如果SomeExternalFunction
确实是编译单元的外部,那么无论你做什么,你几乎都没有机会对编译器进行矢量化。 (我想它可能在链接时,虽然......)并且它也不太可能是“微不足道的”,因为它需要函数调用开销 - 至少如果“琐碎”对你来说意味着和我一样。 (再次,我不知道链接时间优化有多好......)
如果你真的可以保证某些操作不会调整向量的大小,你可以考虑改进你的类的API(或者至少是它的protected
或private
部分)以包含那些自然显而易见的函数不要调整矢量大小。
答案 1 :(得分:2)
大小方法通常由编译器内联,因此会有最小的性能损失,但通常会有一些。
另一方面,这通常仅适用于矢量。例如,如果您使用的是std :: list,则size方法可能非常昂贵。
如果你关心性能,你应该养成使用迭代器和/或std :: for_each等算法的习惯,而不是基于大小的for循环。
答案 2 :(得分:2)
微优化评论可能是因为vector::size()
的两个最常见的实现是
return _Size;
和
return _End - _Begin;
将它们从循环中取出可能不会显着提高性能。
如果每个人都明白可以做到,那么编译器也可能会注意到。使用现代编译器,如果SomeExternalFunction
静态链接,编译器 通常能够查看调用是否可能影响向量的大小。
相信你的编译器!
答案 3 :(得分:0)
在MSVC 2015中,它执行return (this->_Mylast() - this->_Myfirst())
。我不能随便告诉您优化器如何处理此问题。但是除非您的数组为const,否则优化器必须考虑到您可能修改其元素数量的可能性;使其难以优化。在Qt中,它等同于执行return d->size;
的内联函数;也就是说,对于QVector。
我已经在一个正在研究的特定项目中做到了这一点,但这是面向性能代码的。除非您对深度优化有所兴趣,否则我不会打扰。这些方法中的任何一种都可能非常快。在Qt中,它最多是一个指针取消引用,并且具有更多的类型。看起来可以在MSVC中有所作为。
我认为到目前为止,还没有人给出明确的答案。但是,如果您真的要测试它,请让编译器发出程序集源代码,并同时进行两种检查。我不会惊讶地发现高度优化后没有任何区别。但是,请不要忘记,在调试过程中未优化的性能也是很多情况下可能要考虑的因素。涉及数字运算。
我认为OP的原件?确实可以用来说明如何声明数组。