Я работал над простым парсером, и при профилировании я заметил, что узкое место находится в... файле read! Я извлек очень простой тест, чтобы сравнить производительность fstreams
и FILE*
при чтении большого объема данных:
#include <stdio.h>
#include <chrono>
#include <fstream>
#include <iostream>
#include <functional>
void measure(const std::string& test, std::function<void()> function)
{
auto start_time = std::chrono::high_resolution_clock::now();
function();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - start_time);
std::cout<<test<<" "<<static_cast<double>(duration.count()) * 0.000001<<" ms"<<std::endl;
}
#define BUFFER_SIZE (1024 * 1024 * 1024)
int main(int argc, const char * argv[])
{
auto buffer = new char[BUFFER_SIZE];
memset(buffer, 123, BUFFER_SIZE);
measure("FILE* write", [buffer]()
{
FILE* file = fopen("test_file_write", "wb");
fwrite(buffer, 1, BUFFER_SIZE, file);
fclose(file);
});
measure("FILE* read", [buffer]()
{
FILE* file = fopen("test_file_read", "rb");
fread(buffer, 1, BUFFER_SIZE, file);
fclose(file);
});
measure("fstream write", [buffer]()
{
std::ofstream stream("test_stream_write", std::ios::binary);
stream.write(buffer, BUFFER_SIZE);
});
measure("fstream read", [buffer]()
{
std::ifstream stream("test_stream_read", std::ios::binary);
stream.read(buffer, BUFFER_SIZE);
});
delete[] buffer;
}
Результаты запуска этого кода на моей машине:
FILE* write 1388.59 ms
FILE* read 1292.51 ms
fstream write 3105.38 ms
fstream read 3319.82 ms
fstream
запись/чтение примерно в 2 раза медленнее, чем FILE*
write/read! И это при чтении большого блока данных без каких-либо синтаксических разборов или других функций fstreams
. Я запускаю код в Mac OS, Intel I7 2.6GHz, 16 ГБ 1600 МГц, SSD-накопитель. Обратите внимание, что при повторном запуске того же кода время FILE* read
очень низкое (около 200 мс), вероятно, потому, что файл кэшируется... Вот почему файлы, открытые для чтения, не создаются с использованием кода.
Почему при чтении только блога двоичных данных с использованием fstream
происходит настолько медленный по сравнению с FILE*
?
EDIT 1: Я обновил код и время. Извините за задержку!
EDIT 2: Я добавил командную строку и новые результаты (очень похожие на предыдущие!)
$ clang++ main.cpp -std=c++11 -stdlib=libc++ -O3
$ ./a.out
FILE* write 1417.9 ms
FILE* read 1292.59 ms
fstream write 3214.02 ms
fstream read 3052.56 ms
Следуя результатам для второго запуска:
$ ./a.out
FILE* write 1428.98 ms
FILE* read 196.902 ms
fstream write 3343.69 ms
fstream read 2285.93 ms
Похоже, файл кэшируется при чтении как для FILE*
, так и stream
, так как время уменьшается с одинаковой суммой для обоих.
EDIT 3: Я сократил код до этого:
FILE* file = fopen("test_file_write", "wb");
fwrite(buffer, 1, BUFFER_SIZE, file);
fclose(file);
std::ofstream stream("test_stream_write", std::ios::binary);
stream.write(buffer, BUFFER_SIZE);
И начал профайлер. Похоже, что stream
проводит много времени в функции xsputn
, а фактические вызовы write
имеют одинаковую продолжительность (как и должно быть, это одна и та же функция...)
Running Time Self Symbol Name
3266.0ms 66.9% 0,0 std::__1::basic_ostream<char, std::__1::char_traits<char> >::write(char const*, long)
3265.0ms 66.9% 2145,0 std::__1::basic_streambuf<char, std::__1::char_traits<char> >::xsputn(char const*, long)
1120.0ms 22.9% 7,0 std::__1::basic_filebuf<char, std::__1::char_traits<char> >::overflow(int)
1112.0ms 22.7% 2,0 fwrite
1127.0ms 23.0% 0,0 fwrite
EDIT 4 По какой-то причине этот вопрос отмечен как дубликат. Я хотел бы указать, что я вообще не использую printf
, я использую только std::cout
для записи времени. Файлы, используемые в части read
, представляют собой выходные данные из части write
, скопированные с другим именем, чтобы избежать кеширования