2017-10-16 6 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; 
move(startIt, endIt, std::back_inserter(rightVec)); 

:充填のこの方法に比べ

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

は何あなたのベンチマークはつまるところは、ベクトルを充填するこの方法との間の差でありますあなたの2つのコードパスがかなり異なっています。第二版は、二つの理由のために遅くなることが期待されて

:第2のケースで

  • 、ターゲットベクトルは、保管することになっているどのように多くの要素を知っていないので、それはあなたのように成長を維持する必要があります挿入を実行します。成長ベクターは、以前に挿入された要素の再配置およびコピー/移動を伴うので、高価である。この不都合を取り除くには、適切なreseve()コールをmoveの前に挿入します。これにより、このコードパスでのパフォーマンスの低下を大幅に軽減します。
  • パフォーマンスの差が小さいのは、back_inserterに移動し、最初のケースで実行された一括挿入と同じように、ターゲットベクターに要素単位で挿入されるためです。あなたはこれら2点の影響を緩和するために世話をした場合

は、すでに指摘したように、int要素に対して同等の操作を移動し、コピーされている、ので、ランタイムは、ほぼ同じであることを観測します。

1

ベンチマークには欠陥があり、不正確です。

  • まず、使用しているコンパイラフラグは何も言及していません。最適化を有効にしましたか?

  • 最大の問題は、int要素のベクトルを使用していることです。 int移動は、パフォーマンス面では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

関連する問題