2

私の cpp コードは、スペースで区切られた float 値の 7 MB のテキスト ファイルを読み取る必要があります。文字列値を float 配列に解析するのに約 6 秒かかりますが、これは私のユース ケースには多すぎます。

私はオンラインでチェックしてきましたが、通常、時間がかかるのは物理 IO であると人々は言います。これを解消するために、ファイルを一発で文字列ストリームに読み込み、これを float 解析に使用しています。コード速度の改善はまだありません。より速く実行する方法はありますか?

これが私のコードです(簡単にするために、配列エントリを dummy_f に置き換えました):

    #include "stdafx.h"
    #include <iostream>
    #include <fstream>
    #include "time.h"
    #include <sstream>
    using namespace std;

    int main()
    {
      ifstream testfile;
      string filename = "test_file.txt";
      testfile.open(filename.c_str());

      stringstream string_stream;
      string_stream << testfile.rdbuf();

      testfile.close();

      clock_t begin = clock();
      float dummy_f;

      cout<<"started stream at time "<<(double) (clock() - begin) /(double) CLOCKS_PER_SEC<<endl;

      for(int t = 0; t < 6375; t++)
      {

           string_stream >> dummy_f;

           for(int t1 = 0; t1 < 120; t1++)
           {
               string_stream >> dummy_f;
           }
      }

      cout<<"finished stream at time "<<(double) (clock() - begin) /(double) CLOCKS_PER_SEC<<endl;

      string_stream.str("");

      return 0;
     } 

編集:

test_cases.txt ファイルへのリンクは次のとおりですhttps://drive.google.com/file/d/0BzHKbgLzf282N0NBamZ1VW5QeFE/view?usp=sharing

このファイルで実行する場合は、内側のループの次元を 128 に変更してください (入力ミス)。

編集:それを機能させる方法を見つけました。dummy_f を文字列として宣言し、stringstream から文字列ワードとして読み取ります。次に、atof を使用して文字列を float に変換しました。かかった時間は0.4秒で、私には十分です。

  string dummy_f;
  vector<float> my_vector;
  for(int t = 0; t < 6375; t++)
  {

       string_stream >> dummy_f;
       my_vector.push_back(atof(dummy_f.c_str()));
       for(int t1 = 0; t1 < 128; t1++)
       {
           string_stream >> dummy_f;
            my_vector.push_back(atof(dummy_f.c_str()));
       }
  }
4

3 に答える 3

0

update : @Mats とのコメントでの議論は、ロックのオーバーヘッドがこれと関係がある可能性は低いと結論付けたので、Visual C++ のライブラリが float の解析で非常に遅い理由を説明する限り、振り出しに戻ります。あなたのサンプル テスト ファイルは、ほとんどが 1.0 からそれほど離れていないマグニチュードの数値であり、奇妙なことは何もないように見えました。(Agner Fog の表によると、Sandybridge およびそれ以降の Intel の FPU には、いずれにせよ、デノーマルに対するパフォーマンス ペナルティはありません。)

他の人が言ったように、コードをプロファイリングして、どの関数がすべての CPU 時間を消費しているかを調べる時が来ました。また、パフォーマンス カウンターは、分岐の予測ミスやキャッシュ ミスが問題を引き起こしているかどうかを教えてくれます。


cin >> dummy_f別のスレッドが入力バッファーを同時に変更しないようにするために、すべての呼び出しでロックが必要です。4 つまたは 8 つの float を一度に読み取るとscanf("%f%f%f%f", &dummy_array[0], &dummy_array[1], ...)、それがボトルネックである場合、少し効率的になります。(scanf は、関数の引数としてすべての配列要素のアドレスを必要とするため、この点でも優れた API ではありません。ただし、1 回の scanf で複数の変換を使用してアンロールしても、パフォーマンスはわずかに向上します。)

これを stringstream で回避しようとしていますが、効果がある場合とない場合があります。これは関数内のローカル変数であるため、コンパイラがすべての関数を認識してインライン化できる場合、ロックを気にする必要はありません。この変数にアクセスできる他のスレッドは存在できません。

于 2015-08-27T20:21:10.247 に答える
0

私の Linux マシンでは 0.3 秒未満しかかからないため、OP がデバッグ/リリース ビルドで間違いを犯していなければ、Windows に固有の問題であるはずです。

hidden$ cat read-float.cpp 
#include <fstream>
#include <iostream>
#include <vector>
using namespace std;

int main() {
  ifstream fs("/tmp/xx.txt");
  vector<float> v;
  for (int i = 0; i < 6375; i++) {
    for (int j = 0; j < 129; j++) {
      float f;
      fs >> f;
      v.emplace_back(f);
    }
  }
  cout << "Read " << v.size() << " floats" << endl;
}
hidden$ g++ -std=c++11 read-float.cpp -O3
hidden$ time ./a.out 
Read 822375 floats

real    0m0.287s
user    0m0.279s
sys 0m0.008s

hidden$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04) 
于 2015-08-27T21:38:58.417 に答える