2017-07-30 8 views
1

ファイルを1行ずつ読み込むパフォーマンスを比較しようとしています。最初のケースは文字列とistreamのgetline、char *とFILEのgetlineの場合は2番目の場合です。私は疑問に思っています:istreamとFILEで動作するgetlineのパフォーマンスの違い*

  1. なぜ最初のケースは遅いですか
  2. C++スニペットを高速化することは可能ですか

(最初はifstream)以下の出力を考慮してください最初

Lines count: 10628126 
ifstream getline: 43.2684 
Lines count: 10628126 
fopen getline: 1.06217 

FILE *:

Lines count: 10628126 
fopen getline: 1.96065 
Lines count: 10628126 
ifstream getline: 43.0428 

私はテストのために使用されるコード:

#include <fstream> 
#include <iostream> 
#include <string> 

#include <sys/time.h> 
#include <stdio.h> 


using namespace std; 

double gettime() 
{ 
    double result = 0; 
    struct timeval tv = {0}; 
    struct timezone tz = {0}; 
    gettimeofday(&tv, &tz); 
    result = tv.tv_sec + (1.0 * tv.tv_usec/1000000); 
    return result; 
} 

void read_cpp(const char * filename) 
{ 
    ifstream ifile(filename); 
    string line; 
    unsigned int i = 0; 
    while(getline(ifile, line)) i++; 
    cout << "Lines count: " << i << endl; 
} 

void read_c(const char * filename) 
{ 
    FILE * ifile = fopen(filename, "r"); 
    size_t linesz = 4096+1; 
    char * line = new char[linesz]; 
    unsigned int i = 0; 
    while(getline(&line, &linesz, ifile) > 0) i++; 
    delete[] line; 
    cout << "Lines count: " << i << endl; 
    fclose(ifile); 
} 

int main(int argc, char * argv[]) 
{ 
    double tmstart; 
    tmstart = gettime(); 
    read_cpp(argv[1]); 
    cout << "ifstream getline: " << (gettime() - tmstart) << endl; 
    tmstart = gettime(); 
    read_c(argv[1]); 
    cout << "fopen getline: " << (gettime() - tmstart) << endl; 
} 

P.S.私はread_cppとread_cをほとんど違いなく交換しようとしました。

UPDATE @Galikと@gezaをg ++コンパイラを使用して問題を再現することができませんでしたので、私はLinux環境でのコードをチェックし、CCとの間にはほとんど差がないように見えます

++実装。それは環境問題のようです。

$ g++ -v 
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 
Apple LLVM version 8.1.0 (clang-802.0.42) 
Target: x86_64-apple-darwin16.7.0 
Thread model: posix 
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin 

しかし、すべてのそれらのものは、実際の g++で起こったことはありません:もともと私は、Mac OS Xと clang(私にとっては驚き)でデフォルトのC++コンパイラを使用して時間を測定し

$ g++ -v 
Using built-in specs. 
COLLECT_GCC=g++ 
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper 
Target: x86_64-linux-gnu 
Configured with: ... 
Thread model: posix 
gcc version 4.9.2 (Debian 4.9.2-10) 

申し訳ありませんが、みんなご不便をおかけします。

アップデート2

私は、関連トピックclang++ fstreams 10X slower than g++を見つけました。著者はまた、clangによってコンパイルされたコードのパフォーマンス低下に直面しました。この問題を解決するには、デフォルトのもの(-stdlib=libc++)の代わりに別のstdlibの実装()を使用できます。この場合、clangは非推奨の警告が表示されます:

clang: warning: libstdc++ is deprecated; move to libc++ [-Wdeprecated] 

をパフォーマンスが(でも、最適化せずに)ずっと良くなります。

Lines count: 10628126 
fopen getline: 1.02899 
Lines count: 10628126 
ifstream getline: 1.67594 
+1

あなたは() '')( 'read_cpp前に' read_cを起動しようとしている:ここで

は修正バージョンはありますか? –

+0

C++ストリームの方が遅いかもしれません。なぜなら、カーテンの後ろにははるかに多くのことが起こっているからです.C++のstreambufは高速かもしれません。ただし、キャッシングもここで機能している可能性があります。それは両方の読み込み方法を交換し、それがパフォーマンスに顕著な影響を与えるかどうかを調べるために支払うかもしれません(Mike Nakisはこれに勝つ)。 –

+0

@MikeNakis、はい、実際は助けになりません。 read_cは〜1秒遅くなり、read_cppは〜0.2秒早くなりました。 – frist

答えて

1

C++バージョンは、より多くの境界チェックを行い、ロケール解釈とiostream状態管理。非常に堅牢です。

cバージョンは、ミニマリストではるかに脆いです。

安全性と有用性のために価格があります。

その価格は時間です。

更新:

Cのreadlineのが新しい、mallocとfreeを使用していないし、削除することを期待。

#include <cstdlib> 
#include <cstdio> 
#include <iostream> 

void read_c(const char * filename) 
{ 
    FILE * ifile = fopen(filename, "r"); 
    size_t linesz = 0; 
    char * line = nullptr; 
    unsigned int i = 0; 
    while(getline(&line, &linesz, ifile) > 0) i++; 
    free(line); 
    std::cout << "Lines count: " << i << std::endl; 
    fclose(ifile); 
} 
+0

副作用や最適化を最小限に抑えてファイルを読む方法はありますか?言い換えれば、C++ STLを使用してread_cを実装することは可能ですか? – frist

+0

@fristもしあなたが望むものが区切られた文字列であれば、あなたのバージョンは問題ありません。しかし、それをより安全にする方法があります。私は更新を投稿します。 –

+0

私は '' getline() 'を脆いとは言わないでしょう。改行文字で区切られたファイルからチャンクを読み込むだけです。一方、 '[f] scanf()'は有効に使えないという点では脆弱です。 –

関連する問題