http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-Quickly の50:40に、Andrei Alexandrescuがいかに効率が悪い/遅いかについて冗談を言っていますistreamです。
私は過去にostreamが遅く、fwriteがかなり速い(メインループを1回実行するときに何秒も短縮する)という問題を抱えていましたが、なぜなのか理解していませんでした。
C++でistreamとostreamが遅くなる原因は何ですか?または、少なくとも同等にニーズを満たす他のもの(fread/fget、fwriteなど)と比較して遅い。
おそらく、これはあなたが何を扱っているかについていくつかのアイデアを与えることができます:
#include <stdio.h>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <fstream>
#include <time.h>
#include <string>
#include <algorithm>
unsigned count1(FILE *infile, char c) {
int ch;
unsigned count = 0;
while (EOF != (ch=getc(infile)))
if (ch == c)
++count;
return count;
}
unsigned int count2(FILE *infile, char c) {
static char buffer[8192];
int size;
unsigned int count = 0;
while (0 < (size = fread(buffer, 1, sizeof(buffer), infile)))
for (int i=0; i<size; i++)
if (buffer[i] == c)
++count;
return count;
}
unsigned count3(std::istream &infile, char c) {
return std::count(std::istreambuf_iterator<char>(infile),
std::istreambuf_iterator<char>(), c);
}
unsigned count4(std::istream &infile, char c) {
return std::count(std::istream_iterator<char>(infile),
std::istream_iterator<char>(), c);
}
unsigned int count5(std::istream &infile, char c) {
static char buffer[8192];
unsigned int count = 0;
while (infile.read(buffer, sizeof(buffer)))
count += std::count(buffer, buffer+infile.gcount(), c);
count += std::count(buffer, buffer+infile.gcount(), c);
return count;
}
unsigned count6(std::istream &infile, char c) {
unsigned int count = 0;
char ch;
while (infile >> ch)
if (ch == c)
++count;
return count;
}
template <class F, class T>
void timer(F f, T &t, std::string const &title) {
unsigned count;
clock_t start = clock();
count = f(t, 'N');
clock_t stop = clock();
std::cout << std::left << std::setw(30) << title << "\tCount: " << count;
std::cout << "\tTime: " << double(stop-start)/CLOCKS_PER_SEC << "\n";
}
int main() {
char const *name = "equivs2.txt";
FILE *infile=fopen(name, "r");
timer(count1, infile, "ignore");
rewind(infile);
timer(count1, infile, "using getc");
rewind(infile);
timer(count2, infile, "using fread");
fclose(infile);
std::ifstream in2(name);
timer(count3, in2, "ignore");
in2.clear();
in2.seekg(0);
timer(count3, in2, "using streambuf iterators");
in2.clear();
in2.seekg(0);
timer(count4, in2, "using stream iterators");
in2.clear();
in2.seekg(0);
timer(count5, in2, "using istream::read");
in2.clear();
in2.seekg(0);
timer(count6, in2, "using operator>>");
return 0;
}
これを実行すると、次のような結果が得られます(MS VC++を使用)。
ignore Count: 1300 Time: 0.309
using getc Count: 1300 Time: 0.308
using fread Count: 1300 Time: 0.028
ignore Count: 1300 Time: 0.091
using streambuf iterators Count: 1300 Time: 0.091
using stream iterators Count: 1300 Time: 0.613
using istream::read Count: 1300 Time: 0.028
using operator>> Count: 1300 Time: 0.619
そしてこれ(MinGWで):
ignore Count: 1300 Time: 0.052
using getc Count: 1300 Time: 0.044
using fread Count: 1300 Time: 0.036
ignore Count: 1300 Time: 0.068
using streambuf iterators Count: 1300 Time: 0.068
using stream iterators Count: 1300 Time: 0.131
using istream::read Count: 1300 Time: 0.037
using operator>> Count: 1300 Time: 0.121
結果からわかるように、iostreamが非常に遅いということは実際には問題ではありません。むしろ、かなりの程度は、iostreamの使用方法に正確に依存します(そして程度は低いですがFILE *
にも依存します)。また、これらと実装の間にはかなり大きな違いがあります。
それでも、それぞれの最速バージョン(fread
とistream::read
)は基本的に同じです。 VC++を使用すると、getc
はistream::read
またはistreambuf_iterator
よりもかなり遅くなります。
結論:iostreamから良好なパフォーマンスを得るには、FILE *
を使用する場合よりも少し注意が必要ですが、それは確かに可能です。これらはまた、より多くのオプションを提供します:速度をそれほど気にしない場合の利便性、およびわずかな追加作業で、CスタイルのI/Oから得られる最高のものと直接競合するパフォーマンス。
この質問はかなり古いですが、iostreamオブジェクトの構築について誰も言及していません。
つまり、STL iostream
(およびその他のストリームバリアント)を作成するたびに、コードにステップインすると、コンストラクターは内部Init
関数を呼び出します。そこでoperator new
が呼び出され、新しいlocale
オブジェクトが作成されます。同様に、破壊時に破壊されます。
これは恐ろしいです、私見。また、ある時点でシステムロックを使用してメモリが割り当てられたり割り当て解除されたりするため、オブジェクトの構築や破棄が遅くなる原因にもなります。
さらに、一部のSTLストリームではallocator
を指定できますが、なぜlocale
は指定されたアロケーターを使用せずに作成されるのですか?
マルチスレッド環境でストリームを使用すると、新しいストリームオブジェクトが構築されるたびにoperator new
を呼び出すことによって課されるボトルネックを想像することもできます。
私が今自分自身を発見しているので、あなたが私に尋ねたら、恐ろしい混乱です!