簡體   English   中英

在成員函數中循環內部的std :: vector c ++ size()的性能

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

類似的問題,但不太具體: 循環中vector :: size()的性能問題

假設我們在一個成員函數中:

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)中進行優化的情況是:

  • 安全
  • 有明顯的區別
  • 你的編譯器無法自己解決的問題

很少,而且介於兩者之間。

如果只是后兩點,我只是建議你擔心一些不重要的事情。 然而,第一點是真正的殺手鐧:你不想在給自己額外的機會犯錯誤的習慣來獲得。 加速緩慢,正確的代碼比調試快速,錯誤的代碼要容易得多。

現在,那說,我會嘗試回答你的問題。 SomeNotConstFunctionSomeConstFunction函數的定義(推測)在同一個翻譯單元中。 因此,如果這些函數確實不修改向量,編譯器就可以解決它,它只會“調用”一次size

但是,編譯器無法訪問SomeExternalFunction的定義,因此必須假設每次調用該函數都有可能修改向量。 循環中存在該函數可確保每次都調用“大小”。

然而,我把“被叫”放在引號中,因為它是如此微不足道的功能,它幾乎肯定會被內聯。 此外,該功能非常便宜 - 兩個內存查找(幾乎都保證是高速緩存命中),以及減法和右移,或者甚至可以執行兩者的專用單個指令。

即使SomeExternalFunction絕對不做任何事情,每次“調用” size可能性仍然只是循環運行時間的一小部分甚至可以忽略不計。

編輯:響應編輯....

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

您在計算兩個不同版本的代碼時所看到的時間差異。 如果你正在做這樣的非常低級別的優化,你就無法通過“純粹的理由”得到答案 - 你必須憑經驗測試結果。

如果你真的在做這樣的低級優化(並且你可以保證向量不會調整大小),你應該更擔心的是編譯器不知道數組的基指針是不變的,而不是它不知道大小是不變的。

如果SomeExternalFunction確實是編譯單元的外部,那么無論你做什么,你幾乎都沒有機會對編譯器進行矢量化。 (我想它可能在鏈接時,雖然......)並且它也不太可能是“微不足道的”,因為它需要函數調用開銷 - 至少如果“瑣碎”對你來說意味着和我一樣。 (再次,我不知道鏈接時間優化有多好......)

如果你真的可以保證某些操作不會調整向量的大小,你可以考慮改進你的類的API(或者至少是它的protectedprivate部分)來包含那些自然不會調整向量大小的函數。

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的原創? 真的可以用來給出如何聲明數組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM