これまでに集めたものは次のとおりです。
バッファリング:
デフォルトでバッファが非常に小さい場合、バッファ サイズを大きくするとパフォーマンスが確実に向上します。
- HDDのヒット数を減らします
- システムコールの数を減らします
streambuf
バッファーは、基になる実装にアクセスすることで設定できます。
char Buffer[N];
std::ifstream file("file.txt");
file.rdbuf()->pubsetbuf(Buffer, N);
// the pointer reader by rdbuf is guaranteed
// to be non-null after successful constructor
@iavr の厚意による警告: cppreferenceによると、ファイルを開く前に呼び出すことをお勧めしpubsetbuf
ます。それ以外の場合、さまざまな標準ライブラリの実装は異なる動作をします。
ロケール処理:
Locale は、数字や日付が関係する文字変換、フィルタリング、およびより巧妙なトリックを実行できます。それらは動的ディスパッチと仮想呼び出しの複雑なシステムを通過するため、それらを削除するとペナルティ ヒットを削減するのに役立ちます。
デフォルトのC
ロケールは、マシン間で統一されているだけでなく、変換を実行しないことを意図しています。使用するのに適したデフォルトです。
同期:
この機能を使用しても、パフォーマンスの向上は見られませんでした。
static 関数を使用して、グローバル設定 ( の静的メンバー) にアクセスできます。std::ios_base
sync_with_stdio
測定:
gcc 3.4.2
これで遊んで、SUSE 10p3 withを使用してコンパイルされた単純なプログラムをいじりました-O2
。
C: 7.76532e+06
C++: 1.0874e+07
これは、デフォルト コードの約20%
... の速度低下を表します。実際、バッファー (C または C++) または同期パラメーター (C++) を改ざんしても、改善は見られませんでした。
他の人による結果:
@Irfy on g++ 4.7.2-2ubuntu1、-O3、仮想化された Ubuntu 11.10、3.5.0-25-generic、x86_64、十分な RAM/CPU、196MB の複数の「find / >> largefile.txt」実行
C: 634572 C++: 473222
C++ 25% 高速化
@Matteo Italia on g++ 4.4.5、-O3、Ubuntu Linux 10.10 x86_64、ランダムな 180 MB ファイル
C: 910390
C++: 776016
C++ 17% 高速化
@Bogatyr on g++ i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5664)、mac mini、4GB RAM、168MB データファイルを使用したこのテストを除いてアイドル状態
C: 4.34151e+06
C++: 9.14476e+06
C++ 111% 遅い
@Asu on clang++ 3.8.0-2ubuntu4、Kubuntu 16.04 Linux 4.8-rc3、8GB RAM、i5 Haswell、Crucial SSD、88MB データファイル (tar.xz アーカイブ)
C: 270895 C++: 162799
C++ 66% 高速化
答えは次のとおりです。これは実装の品質の問題であり、実際にはプラットフォームに依存します:/
ベンチマークに関心のある方向けの完全なコードは次のとおりです。
#include <fstream>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <cstdio>
#include <sys/time.h>
template <typename Func>
double benchmark(Func f, size_t iterations)
{
f();
timeval a, b;
gettimeofday(&a, 0);
for (; iterations --> 0;)
{
f();
}
gettimeofday(&b, 0);
return (b.tv_sec * (unsigned int)1e6 + b.tv_usec) -
(a.tv_sec * (unsigned int)1e6 + a.tv_usec);
}
struct CRead
{
CRead(char const* filename): _filename(filename) {}
void operator()() {
FILE* file = fopen(_filename, "r");
int count = 0;
while ( fscanf(file,"%s", _buffer) == 1 ) { ++count; }
fclose(file);
}
char const* _filename;
char _buffer[1024];
};
struct CppRead
{
CppRead(char const* filename): _filename(filename), _buffer() {}
enum { BufferSize = 16184 };
void operator()() {
std::ifstream file(_filename, std::ifstream::in);
// comment to remove extended buffer
file.rdbuf()->pubsetbuf(_buffer, BufferSize);
int count = 0;
std::string s;
while ( file >> s ) { ++count; }
}
char const* _filename;
char _buffer[BufferSize];
};
int main(int argc, char* argv[])
{
size_t iterations = 1;
if (argc > 1) { iterations = atoi(argv[1]); }
char const* oldLocale = setlocale(LC_ALL,"C");
if (strcmp(oldLocale, "C") != 0) {
std::cout << "Replaced old locale '" << oldLocale << "' by 'C'\n";
}
char const* filename = "largefile.txt";
CRead cread(filename);
CppRead cppread(filename);
// comment to use the default setting
bool oldSyncSetting = std::ios_base::sync_with_stdio(false);
double ctime = benchmark(cread, iterations);
double cpptime = benchmark(cppread, iterations);
// comment if oldSyncSetting's declaration is commented
std::ios_base::sync_with_stdio(oldSyncSetting);
std::cout << "C : " << ctime << "\n"
"C++: " << cpptime << "\n";
return 0;
}