2017-10-16 128 views
-2

我寫了一個小的測試比較舉動和測試語義:移動語義慢然後複製C++

#include <vector> 
#include <iostream> 
#include <iterator> 
#include <chrono> 
#include <iomanip> 

using namespace std; 

int main() 
{ 

    int lenLeft = 3; 
    int lenMid = 3; 
    vector<int> lenVec{10,100,1000,static_cast<int>(1e4),static_cast<int>(1e5),static_cast<int>(1e6),static_cast<int>(1e7)}; 
    int reps = 100; 
    vector<double>delta_t_move; 
    vector<double>delta_t_copy; 


    //move 
    cout<<"move"<<endl; 
    { 

     for(int len : lenVec) 
     { 
      auto startTime = std::chrono::high_resolution_clock::now(); 

      for(int i = 0; i<reps;i++) 
      { 
       vector<int> leftVec(len,0); 

       vector<int> rightVec; 
       move(leftVec.begin()+lenLeft+lenMid,leftVec.end(),std::back_inserter(rightVec)); 
       leftVec.erase(leftVec.begin()+lenLeft+lenMid,leftVec.end()); 

       vector<int> midVec; 
       std::move(leftVec.begin()+lenLeft,leftVec.begin()+lenLeft+lenMid,std::back_inserter(midVec)); 
       leftVec.erase(leftVec.begin()+lenLeft,leftVec.begin()+lenLeft+lenMid); 
      } 

      auto endTime = std::chrono::high_resolution_clock::now(); 
      std::chrono::duration<double> elapsed = endTime - startTime; 
      delta_t_move.push_back(elapsed.count()); 
     } 
    } 

    //copy 
    cout<<"copy"<<endl; 
    { 

     for(int len : lenVec) 
     { 

      auto startTime = std::chrono::high_resolution_clock::now(); 

      for(int i = 0; i<reps;i++) 
      { 
       vector<int> leftVec(len,0); 

       vector<int> rightVec = vector<int>(leftVec.begin()+lenLeft+lenMid,leftVec.end()); 
       leftVec.erase(leftVec.begin()+lenLeft+lenMid,leftVec.end()); 

       vector<int> midVec = vector<int>(leftVec.begin()+lenLeft,leftVec.begin()+lenLeft+lenMid); 
       leftVec.erase(leftVec.begin()+lenLeft,leftVec.begin()+lenLeft+lenMid); 
      } 

      auto endTime = std::chrono::high_resolution_clock::now(); 
      std::chrono::duration<double> elapsed = endTime - startTime; 
      delta_t_copy.push_back(elapsed.count()); 
     } 
    } 

    for(int i = 0; i<lenVec.size();i++) 
    { 
     cout<<"lenVec = "<<setw(40)<<lenVec.at(i)<<"\t\t : delta_t_copy/delta_t_move = "<< delta_t_copy.at(i)/delta_t_move.at(i)<<endl; 
    } 


    return 0; 
} 

我得到這個程序的輸出是:

move 
copy 
lenVec = 10 : delta_t_copy/delta_t_move = 0.431172 
lenVec = 100 : delta_t_copy/delta_t_move = 0.257102 
lenVec = 1000 : delta_t_copy/delta_t_move = 0.166006 
lenVec = 10000 : delta_t_copy/delta_t_move = 0.108573 
lenVec = 100000 : delta_t_copy/delta_t_move = 0.113769 
lenVec = 1000000 : delta_t_copy/delta_t_move = 0.134912 
lenVec = 10000000 : delta_t_copy/delta_t_move = 0.133874 

我劈開初始向量尺寸爲len,分成3件。第一塊長度爲3,中間長度爲3,其餘尺寸爲len-6。 我的結果顯示覆制語義要比移動語義快得多。

我正在使用MSVC2015。

任何想法如何可以是真實的?移動語義在什麼情況下更快?

+0

發佈[MCVE],而不是指向博客文章的鏈接。 –

+0

哦,我喜歡通過代碼橫向滾動...... – DeiDei

+2

除此之外,你正在「移動」int。這是沒有意義的。 – DeiDei

回答

1

Vittorio's answer之外,讓我指出具體會導致"move"代碼路徑中性能下降的原因。

是什麼您的基準歸結爲填充載體的這種方式的區別:

vector<int> rightVec = vector<int>(startIt, endIt); 

相比,這種方式填充:

vector<int> rightVec; 
move(startIt, endIt, std::back_inserter(rightVec)); 

由於這是唯一部分其中你的兩個代碼路徑差別很大。

第二個版本預計將有兩個原因較慢:

  • 在第二種情況下,目標矢量不知道它有多少元素應該存儲,所以它必須保持增長,你執行插入。越來越多的載體是昂貴的,因爲它涉及重新分配和複製/移動先前插入的元素。您可以通過在move之前插入適當的reseve()呼叫來消除此缺點。這將大大降低此代碼路徑上的性能損失。
  • 剩下的小的性能差異將歸因於您移動到back_inserter這一事實,這導致按照元素方式插入到目標向量,正如在第一種情況下執行批量插入一樣。

如果你照顧,以減輕這兩點的影響,你會觀察到的運行時大致相當,因爲正如已經指出的那樣,int要素移動和複製是等價的操作。

1

你的基準是有缺陷和不精確的。

  • 首先,你永遠不會提到你使用的是什麼編譯器標誌 - 你是否啓用了優化?

  • 最大的問題是您使用的矢量元素爲intint移動相當於int複製的性能。

  • 對於一個正確和完整的基準,你也應該嘗試g ++和clang ++。

  • 您不在任何地方撥打std::vector<T>::reserve

  • 雖然不太可能,但不能保證編譯器不會積極優化您的環路(例如展開或融合多個週期)


你也是你的 「複製」 基準進行一些不必要的動作:

vector<int> rightVec = vector<int>(leftVec.begin()+lenLeft+lenMid,leftVec.end());  
vector<int> midVec = vector<int>(leftVec.begin()+lenLeft,leftVec.begin()+lenLeft+lenMid); 

爲什麼不......

vector<int> rightVec(leftVec.begin()+lenLeft+lenMid,leftVec.end());  
vector<int> midVec(leftVec.begin()+lenLeft,leftVec.begin()+lenLeft+lenMid); 

...?

+0

我應用了你們推薦的更改,但仍然存在性能差異。 – newandlost