简体   繁体   English

在成员函数中循环内部的std :: vector c ++ size()的性能

[英]performance of std::vector c++ size() inside loop in member function

Similar question, but less specific: Performance issue for vector::size() in a loop 类似的问题,但不太具体: 循环中vector :: size()的性能问题

Suppose we're in a member function like: 假设我们在一个成员函数中:

void  Object::DoStuff()  {

   for( int k = 0; k < (int)this->m_Array.size(); k++ )
   {  
       this->SomeNotConstFunction();
       this->ConstFunction();

       double x = SomeExternalFunction(i);
   }
}

1) I'm willing to believe that if only the "SomeExternalFunction" is called that the compiler will optimize and not redundantly call size() on m_Array ... is this the case? 1)我愿意相信,如果仅调用“SomeExternalFunction”,编译器将优化而不是冗余地调用m_Array上的size()......是这样吗?

2) Wouldn't you almost certainly get a boost in speed from doing 2)你几乎肯定不会从速度上提高速度

  int N = m_Array.size()
  for( int k = 0; k < N; k++ ) { ... } 

if you're calling some member function that is not const ? 如果你正在调用一些非const的成员函数?

Edit Not sure where these down-votes and snide comments about micro-optimization are coming from, perhaps I can clarify: 编辑不确定这些关于微优化的低票和讽刺评论来自哪里,也许我可以澄清一下:

Firstly, it's not to optimize per-se but just understand what the compiler will and will not fix. 首先,它不是要优化本身,而是要了解编译器将要修复的内容。 Usually I use the size() function but I ask now because here the array might have millions of data points. 通常我使用size()函数,但我现在问,因为这里数组可能有数百万个数据点。

Secondly, the situation is that "SomeNotConstFunction" might have a very rare chance of changing the size of the array, or its ability to do so might depend on some other variable being toggled. 其次,情况是“SomeNotConstFunction”可能极有可能改变数组的大小,或者它的能力可能取决于其他一些被切换的变量。 So, I'm asking at what point will the compiler fail, and what exactly is the time cost incurred by size() when the array really might change, despite human-known reasons that it won't? 所以,我问的是编译器会在什么时候失败,以及当数组确实可能发生变化时size()的时间成本到底是多少,尽管人为已知的原因不会?

Third, the operations in-loop are pretty trivial, there are just millions of them but they are embarrassingly parallel. 第三,循环中的操作非常简单,只有数百万,但它们是令人尴尬的并行。 I would hope that by externally placing the value would let the compiler vectorize some of the work. 我希望通过外部放置值可以让编译器矢量化一些工作。

Do not get into the habit of doing things like that. 不要养成这样做的习惯。

The cases where the optimization you make in (2) is: 您在(2)中进行优化的情况是:

  • safe to do 安全
  • has a noticeable difference 有明显的区别
  • something your compiler cannot figure out on its own 你的编译器无法自己解决的问题

are few and far in-between. 很少,而且介于两者之间。

If it were just the latter two points, I would just advise that you're worrying about something unimportant. 如果只是后两点,我只是建议你担心一些不重要的事情。 However, that first point is the real killer: you do not want to get in the habit of giving yourself extra chances to make mistakes. 然而,第一点是真正的杀手锏:你不想在给自己额外的机会犯错误的习惯来获得。 It's far, far easier to accelerate slow, correct code than it is to debug fast, buggy code. 加速缓慢,正确的代码比调试快速,错误的代码要容易得多。

Now, that said, I'll try answering your question. 现在,那说,我会尝试回答你的问题。 The definitions of the functions SomeNotConstFunction and SomeConstFunction are (presumably) in the same translation unit. SomeNotConstFunctionSomeConstFunction函数的定义(推测)在同一个翻译单元中。 So if these functions really do not modify the vector, the compiler can figure it out, and it will only "call" size once. 因此,如果这些函数确实不修改向量,编译器就可以解决它,它只会“调用”一次size

However, the compiler does not have access to the definition of SomeExternalFunction , and so must assume that every call to that function has the potential of modifying your vector. 但是,编译器无法访问SomeExternalFunction的定义,因此必须假设每次调用该函数都有可能修改向量。 The presence of that function in your loop guarantees that `size is "called" every time. 循环中存在该函数可确保每次都调用“大小”。

I put "called" in quotes, however, because it is such a trivial function that it almost certainly gets inlined. 然而,我把“被叫”放在引号中,因为它是如此微不足道的功能,它几乎肯定会被内联。 Also, the function is ridiculously cheap -- two memory lookups (both nearly guaranteed to be cache hits), and either a subtraction and a right shift, or maybe even a specialized single instruction that does both. 此外,该功能非常便宜 - 两个内存查找(几乎都保证是高速缓存命中),以及减法和右移,或者甚至可以执行两者的专用单个指令。

Even if SomeExternalFunction does absolutely nothing, it's quite possible that "calling" size every time would still only be a small-to-negligible fraction of the running time of your loop. 即使SomeExternalFunction绝对不做任何事情,每次“调用” size可能性仍然只是循环运行时间的一小部分甚至可以忽略不计。

Edit: In response to the edit.... 编辑:响应编辑....

what exactly is the time cost incurred by size() when the array really might change

The difference in the times you see when you time the two different versions of code. 您在计算两个不同版本的代码时所看到的时间差异。 If you're doing very low level optimizations like that, you can't get answers through "pure reason" -- you must empirically test the results. 如果你正在做这样的非常低级别的优化,你就无法通过“纯粹的理由”得到答案 - 你必须凭经验测试结果。

And if you really are doing such low level optimizations (and you can guarantee that the vector won't resize), you should probably be more worried about the fact the compiler doesn't know the base pointer of the array is constant, rather than it not knowing the size is constant. 如果你真的在做这样的低级优化(并且你可以保证向量不会调整大小),你应该更担心的是编译器不知道数组的基指针是不变的,而不是它不知道大小是不变的。

If SomeExternalFunction really is external to the compilation unit, then you have pretty much no chance of the compiler vectorizing the loop, no matter what you do. 如果SomeExternalFunction确实是编译单元的外部,那么无论你做什么,你几乎都没有机会对编译器进行矢量化。 (I suppose it might be possible at link time, though....) And it's also unlikely to be "trivial" because it requires function call overhead -- at least if "trivial" means the same thing to you as to me. (我想它可能在链接时,虽然......)并且它也不太可能是“微不足道的”,因为它需要函数调用开销 - 至少如果“琐碎”对你来说意味着和我一样。 (again, I don't know how good link time optimizations are....) (再次,我不知道链接时间优化有多好......)

If you really can guarantee that some operations will not resize the vector, you might consider refining your class's API (or at least it's protected or private parts) to include functions that self-evidently won't resize the vector. 如果你真的可以保证某些操作不会调整向量的大小,你可以考虑改进你的类的API(或者至少是它的protectedprivate部分)来包含那些自然不会调整向量大小的函数。

The size method will typically be inlined by the compiler, so there will be a minimal performance hit, though there will usually be some . size方法通常由编译器内联,因此会有最小的性能损失,尽管通常会有一些

On the other hand, this is typically only true for vectors. 另一方面,这通常仅适用于矢量。 If you are using a std::list, for instance, the size method can be quite expensive. 例如,如果您使用的是std :: list,则size方法可能非常昂贵。

If you are concerned with performance, you should get in the habit of using iterators and/or algorithms like std::for_each, rather than a size-based for loop. 如果你关心性能,你应该养成使用迭代器和/或std :: for_each等算法的习惯,而不是基于大小的for循环。

The micro optimization remarks are probably because the two most common implementations of vector::size() are 微优化备注可能是因为vector::size()的两个最常见的实现是

return _Size;

and

return _End - _Begin;

Hoisting them out of the loop will probably not noticably improve the performance. 将它们从环路中吊出可能不会显着提高性能。

And if it is obvious to everyone that it can be done, the compiler is also likely to notice. 如果每个人都明白它可以做到,编译器也可能会注意到。 With modern compilers, and if SomeExternalFunction is statically linked, the compiler is usually able to see if the call might affect the vector's size. 随着现代编译器,如果SomeExternalFunction静态链接,编译器通常能够看到,如果调用可能会影响矢量的大小。

Trust your compiler! 相信你的编译器!

In MSVC 2015, it does a return (this->_Mylast() - this->_Myfirst()) . 在MSVC 2015中,它return (this->_Mylast() - this->_Myfirst()) I can't tell you offhand just how the optimizer might deal with this; 我不能随便告诉你优化器如何处理这个问题; but unless your array is const, the optimizer must allow for the possibility that you may modify its number of elements; 但除非您的数组是const,否则优化器必须允许您修改其元素数量; making it hard to optimize out. 使其难以优化。 In Qt, it equates to an inline function that that does a return d->size; 在Qt中,它等同于内联函数,它return d->size; ; ; that is, for a QVector. 也就是说,对于QVector。

I've taken to doing it in one particular project I'm working on, but it is for performance-oriented code. 我已经开始在我正在开发的一个特定项目中完成它,但它适用于面向性能的代码。 Unless you are interested in deeply optimizing something, I wouldn't bother. 除非你有兴趣深入优化某些东西,否则我不会打扰。 It probably is pretty fast any of these ways. 任何这些方式都可能非常快。 In Qt, it is at most one pointer dereferencing, and is more typing. 在Qt中,最多只有一个指针解除引用,并且更多的是打字。 It looks like it could make a difference in MSVC. 看起来它可能会对MSVC产生影响。

I think nobody has offered a definitive answer so far; 到目前为止,我认为没有人提供明确的答案; but if you really want to test it, have the compiler emit assembly source code, and inspect it both ways. 但如果你真的想测试它,让编译器发出汇编源代码,并检查它两种方式。 I wouldn't be surprised to find that there's no difference when highly optimized. 如果发现高度优化没有区别,我不会感到惊讶。 Let's not forget, though, that unoptimized performance during debug is also a factor that might be taken into consideration, when a lot of eg number crunching is involved. 但是,我们不要忘记,在涉及大量例如数字运算时,调试期间未优化的性能也是可以考虑的因素。

I think the OP's original ? 我认为OP的原创? really could use to give how the array is declared. 真的可以用来给出如何声明数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM