Недавно я решил оптимизировать чтение файла, которое я делал, потому что, как все говорят, чтение большого куска данных в буфер и последующая работа с ним быстрее, чем использование большого количества маленьких операций чтения. И мой код, безусловно, теперь намного быстрее, но после некоторого профилирования оказывается, что memcpy занимает много времени.
Суть моего кода такова...
ifstream file("some huge file");
char buffer[0x1000000];
for (yada yada) {
int size = some arbitrary size usually around a megabyte;
file.read(buffer, size);
//Do stuff with buffer
}
Я использую Visual Studio 11, и после профилирования моего кода он говорит ifstream::read()
в итоге вызывает xsgetn()
, который копирует из внутреннего буфера в мой буфер. Эта операция занимает более 80% времени! На втором месте uflow()
, который занимает 10% времени.
Можно ли обойти это копирование? Могу ли я каким-то образом указать ifstream
буферизовать нужный мне размер прямо в мой буфер? Использует ли C-стиль FILE*
такой внутренний буфер?
ОБНОВЛЕНИЕ: Из-за того, что люди посоветовали мне использовать cstdio... Я провел тест.
РЕДАКТИРОВАТЬ: К сожалению, старый код был полон ошибок (он даже не читал весь файл!). Вы можете увидеть это здесь: http://pastebin.com/4dGEQ6S7
Вот мой новый тест:
const int MAX = 0x10000;
char buf[MAX];
string fpath = "largefile";
int main() {
{
clock_t start = clock();
ifstream file(fpath, ios::binary);
while (!file.eof()) {
file.read(buf, MAX);
}
clock_t end = clock();
cout << end-start << endl;
}
{
clock_t start = clock();
FILE* file = fopen(fpath.c_str(), "rb");
setvbuf(file, NULL, _IOFBF, 1024);
while (!feof(file)) {
fread(buf, 0x1, MAX, file);
}
fclose(file);
clock_t end = clock();
cout << end-start << endl;
}
{
clock_t start = clock();
HANDLE file = CreateFile(fpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL, NULL);
while (true) {
DWORD used;
ReadFile(file, buf, MAX, &used, NULL);
if (used < MAX) break;
}
CloseHandle(file);
clock_t end = clock();
cout << end-start << endl;
}
system("PAUSE");
}
Время:
185
80
78
Ну... похоже, использование fread в стиле C работает быстрее, чем ifstream::read. Кроме того, использование Windows ReadFile дает лишь небольшое преимущество, которое незначительно (я посмотрел на код, и fread в основном является оболочкой для ReadFile). Похоже, я все-таки перейду на фред.
Чувак, как сложно писать бенчмарк, который на самом деле правильно тестирует все это.
ЗАКЛЮЧЕНИЕ: Использование
быстрее, чем
. Причина, по которой fstream работает медленнее, заключается в том, что потоки С++ имеют собственный внутренний буфер. Это приводит к дополнительному копированию всякий раз, когда вы читаете/записываете, и на это копирование приходится все дополнительное время, затрачиваемое fstream. Еще более шокирующим является то, что дополнительное время, затрачиваемое на чтение файла, больше, чем время, необходимое для фактического чтения файла.