在成员函数中循环内部的std :: vector c ++ size()的性能
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在成员函数中循环内部的std :: vector c ++ size()的性能相关的知识,希望对你有一定的参考价值。
类似的问题,但不太具体: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()的时间成本到底是多少,尽管人为已知的原因不会?
第三,循环中的操作非常简单,只有数百万,但它们是令人尴尬的并行。我希望通过外部放置值可以让编译器矢量化一些工作。
不要养成这样做的习惯。
您在(2)中进行优化的情况是:
- 安全
- 有明显的区别
- 你的编译器无法自己解决的问题
很少,而且介于两者之间。
如果只是后两点,我只是建议你担心一些不重要的事情。然而,第一点是真正的杀手:你不想养成给自己犯错的机会。加速缓慢,正确的代码比调试快速,错误的代码要容易得多。
现在,那说,我会尝试回答你的问题。函数SomeNotConstFunction
和SomeConstFunction
的定义(推测)在相同的翻译单元中。因此,如果这些函数确实不修改向量,编译器可以解决它,它只会“调用”size
一次。
但是,编译器无法访问SomeExternalFunction
的定义,因此必须假设每次调用该函数都有可能修改向量。循环中存在该函数可确保每次都调用“大小”。
然而,我把“被叫”放在引号中,因为它是如此微不足道的功能,它几乎肯定会被内联。此外,该功能非常便宜 - 两个内存查找(几乎都保证是高速缓存命中),以及减法和右移,或者甚至可以执行两者的专用单个指令。
即使SomeExternalFunction
绝对没有做任何事情,很可能每次“调用”size
仍然只是循环运行时间的一小部分甚至可以忽略不计。
编辑:响应编辑....
what exactly is the time cost incurred by size() when the array really might change
您在计算两个不同版本的代码时所看到的时间差异。如果你正在做这样的非常低级别的优化,你就无法通过“纯粹的理由”得到答案 - 你必须凭经验测试结果。
如果你真的在做这样的低级优化(并且你可以保证向量不会调整大小),你应该更担心的是编译器不知道数组的基指针是不变的,而不是它不知道大小是不变的。
如果SomeExternalFunction
确实在编译单元的外部,那么无论你做什么,你几乎都没有机会对编译器进行矢量化。 (我想它可能在链接时,虽然......)并且它也不太可能是“微不足道的”,因为它需要函数调用开销 - 至少如果“琐碎”对你来说意味着和我一样。 (再次,我不知道链接时间优化有多好......)
如果你真的可以保证某些操作不会调整向量的大小,你可以考虑改进你的类的API(或者至少是它的protected
或private
部分)来包含那些自然不会调整向量大小的函数。
size方法通常由编译器内联,因此会有最小的性能损失,尽管通常会有一些。
另一方面,这通常仅适用于矢量。例如,如果您使用的是std :: list,则size方法可能非常昂贵。
如果你关心性能,你应该养成使用迭代器和/或std :: for_each等算法的习惯,而不是基于大小的for循环。
微优化评论可能是因为vector::size()
的两个最常见的实现
return _Size;
和
return _End - _Begin;
将它们从环路中吊出可能不会显着提高性能。
如果每个人都明白它可以做到,编译器也可能会注意到。使用现代编译器,如果SomeExternalFunction
静态链接,编译器通常能够查看调用是否可能影响向量的大小。
相信你的编译器!
在MSVC 2015中,它有一个return (this->_Mylast() - this->_Myfirst())
。我不能随便告诉你优化器如何处理这个问题;但除非您的数组是const,否则优化器必须允许您修改其元素数量;使其难以优化。在Qt中,它等同于内联函数,它执行return d->size;
;也就是说,对于QVector。
我已经开始在我正在开发的一个特定项目中完成它,但它适用于面向性能的代码。除非你有兴趣深入优化某些东西,否则我不会打扰。任何这些方式都可能非常快。在Qt中,最多只有一个指针解除引用,并且更多的是打字。看起来它可能会对MSVC产生影响。
到目前为止,我认为没有人提供明确的答案;但如果你真的想测试它,让编译器发出汇编源代码,并检查它两种方式。如果发现高度优化没有区别,我不会感到惊讶。但是,我们不要忘记,在调试期间未经优化的性能也是一个可以考虑的因素,当很多例如涉及数字运算。
我认为OP的原创?真的可以用来给出如何声明数组。
以上是关于在成员函数中循环内部的std :: vector c ++ size()的性能的主要内容,如果未能解决你的问题,请参考以下文章
在XCode 4中调试时查看内部 std :: vector数据
std::vector 类与非成员函数(连同 typedef)[关闭]
具有显式析构函数和 std::unique_ptr<> 成员的类不能在 std::vector<> 中使用?