Вот что я собрала до сих пор:
Буферизация
Если по умолчанию буфер очень маленький, увеличение размера буфера может определенно улучшить производительность:
- уменьшает количество обращений к жесткому диску
- уменьшает количество системных вызовов
Буфер может быть установлен путем доступа к базовой реализации 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
перед открытием файла. В противном случае различные реализации стандартной библиотеки имеют различное поведение.
Обработка локали:
Локаль может выполнять преобразование символов, фильтрацию и другие хитрые трюки с числами или датами. Они проходят сложную систему динамической диспетчеризации и виртуальных вызовов, поэтому их удаление может помочь уменьшить штрафной удар.
Язык по умолчанию C
не предназначен для выполнения какого-либо преобразования, а также является единообразным на разных машинах. Это хороший вариант по умолчанию.
Синхронизация:
Я не смог увидеть улучшения производительности при использовании этого средства.
Можно получить доступ к настройке global (статический член std::ios_base
), используя статическую функцию sync_with_stdio
.
Размеры:
Играя с этим, я играл с простой программой, скомпилированной с помощью gcc 3.4.2
на SUSE 10p3 с -O2
.
C: 7,76532e + 06
C ++: 1.0874e + 07
Что представляет собой замедление примерно 20%
... для кода по умолчанию. Действительно, вмешательство в буфер (в C или C ++) или в параметры синхронизации (C ++) не принесло никаких улучшений.
Результаты других:
@ Irfy на g ++ 4.7.2-2ubuntu1, -O3, виртуализированный Ubuntu 11.10, универсальный 3.5.0-25, x86_64, достаточно ram / cpu, 196 МБ из нескольких «find / >> largefile.txt» работает
C: 634572
C ++: 473222
C ++ 25% быстрее
@ Matteo Italia на g ++ 4.4.5, -O3, Ubuntu Linux 10.10 x86_64 со случайным файлом 180 МБ
C: 910390
С ++: 776016
C ++ 17% быстрее
@ Bogatyr на g ++ i686-apple-darwin10-g ++ - 4.2.1 (GCC) 4.2.1 (Apple Inc., сборка 5664), mac mini, 4 ГБ оперативной памяти, в режиме ожидания, за исключением этого теста с файлом данных 168 МБ
C: 4,34151e + 06
C ++: 9.14476e + 06
C ++ 111% медленнее
@ Asu на clang ++ 3.8.0-2ubuntu4, Kubuntu 16.04 Linux 4.8-rc3, ram 8 ГБ, i5 Haswell, Crucial SSD, файл данных 88 МБ (архив tar.xz)
C: 270895
С ++: 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;
}