Вот что я собрал до сих пор:
Буферизация:
Если по умолчанию буфер очень мал, увеличение размера буфера определенно может улучшить производительность:
- уменьшает количество обращений к жесткому диску
- уменьшает количество системных вызовов
Буфер можно установить, обратившись к базовой реализации 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
по умолчанию не предназначен для выполнения каких-либо преобразований, а также является единым для всех компьютеров. Это хорошее значение по умолчанию.
Синхронизация:
Я не увидел улучшения производительности при использовании этого средства.
Доступ к глобальному параметру (статическому элементу 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, достаточно оперативной памяти/процессора, 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
C++: 776016
C++ на 17% быстрее
@Bogatyr на g++ i686-apple-darwin10-g++-4.2.1 (GCC) 4.2.1 (Apple Inc. build 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, 8 ГБ оперативной памяти, i5 Haswell, Crucial SSD, файл данных 88 МБ (архив 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;
}
person
Matthieu M.
schedule
02.03.2011
comp.lang.c++.moderated
было местом, где происходили все интересные обсуждения C++ в 90-х.) - person sbi   schedule 02.03.2011std::ios_base::sync_with_stdio
. - person Konrad Rudolph   schedule 02.03.2011scanf()
. Конечно, поскольку это разделяет все недостаткиscanf()
и добавляет несколько слоев поверх, эта реализация потока, в конечном счете, будет медленнее. И я говорю здесь не о дисковом вводе-выводе, а о чистом синтаксическом анализе. Теоретически потоки могут быть даже быстрее, чемprintf()
/scanf()
, но я еще не встречал такой реализации в дикой природе. - person sbi   schedule 02.03.2011