即使使用現代編譯器,第一個版本通常也會更快。優化器難以證明,由於寫入循環體的位置出現混淆,大小不會改變,因此在許多情況下,第二個版本將不得不在每次循環迭代中重新計算大小。
我在Visual Studio 2013 Release中對此進行了測量,發現32位和64位代碼的性能差異。兩個版本都被std :: fill()方便地打敗了。這些測量結果的平均值超過1000次運行,有1000萬個元素矢量(隨着內存訪問變得更加瓶頸,將元素數量增加到10億有點降低了性能差異)。
Method Time relative to uncached for loop
x86 x64
uncached for loop 1.00 1.00
cached for loop 0.70 0.98
std::fill() 0.42 0.57
基線緩存大小循環代碼:
const auto size = vec.size();
for (vector<int>::size_type i = 0; i < size; ++i) {
vec[i] = val;
}
編譯這個循環體(86版):
00B612C0 mov ecx,dword ptr [esi]
00B612C2 mov dword ptr [ecx+eax*4],edi
00B612C5 inc eax
00B612C6 cmp eax,edx
00B612C8 jb forCachedSize+20h (0B612C0h)
雖然不緩存矢量大小的版本:
for (vector<int>::size_type i = 0; i < vec.size(); ++i) {
vec[i] = val;
}
Com堆到這,每次通過循環重新計算vec.size():
00B612F0 mov dword ptr [edx+eax*4],edi
00B612F3 inc eax
00B612F4 mov ecx,dword ptr [esi+4] <-- Load vec.end()
00B612F7 mov edx,dword ptr [esi] <-- Load vec.begin()
00B612F9 sub ecx,edx <-- ecx = vec.end() - vec.begin()
00B612FB sar ecx,2 <-- exc = (vec.end() - vec.begin())/sizeof(int)
00B612FE cmp eax,ecx
00B61300 jb forComputedSize+20h (0B612F0h)
任何像樣的編譯器*應*優化第二個;但唯一確定的方法是衡量它。 'for(auto&x:myVec)x = 0;'?或'std :: fill(myVec.begin(),myVec.end(),0)'? – 2014-08-27 16:31:44
謝謝,我發佈的原因是因爲我喜歡瞭解大多數編譯器的行爲,而不僅僅是我目前使用的行爲。分析只告訴我有關當前編譯器 – 2014-08-27 16:34:13
[循環中vector :: size()的性能問題]的重複可能性(http://stackoverflow.com/questions/3901630/performance-issue-for-vectorsize-in-a -loop) – quantdev 2014-08-27 16:34:30