Я написал следующий простой тестовый код, который создает 10 000 пустых файлов .txt в подкаталоге.
#include <iostream>
#include <time.h>
#include <string>
#include <fstream>
void CreateFiles()
{
int i = 1;
while (i <= 10000) {
int filename = i;
std::string string_i = std::to_string(i);
std::string file_dir = ".\\results\\"+string_i+".txt";
std::ofstream outfile(file_dir);
i++;
}
}
int main()
{
clock_t tStart1 = clock();
CreateFiles();
printf("\nHow long it took to make files: %.2fs\n", (double)(clock() - tStart1)/CLOCKS_PER_SEC);
std::cin.get();
return 0;
}
Все нормально работает. Все 10 000 файлов .txt создаются в течение ~3.55 секунд. (используя мой компьютер)
Вопрос 1: Игнорируя преобразование из int в std::string и т. д., Есть ли что-нибудь, что я мог бы здесь оптимизировать, чтобы программа могла быстрее создавать файлы? Я конкретно имею в виду использование std::ofstream outfile - возможно, использование чего-то другого было бы значительно быстрее?
Тем не менее, ~3,55 секунды удовлетворительны по сравнению со следующим:
Я изменил функцию так, чтобы прямо сейчас она также заполняла файлы .txt некоторыми случайными целочисленными данными i и некоторым постоянным текстом:
void CreateFiles()
{
int i = 1;
while (i <= 10000) {
int filename = i;
std::string string_i = std::to_string(i);
std::string file_dir = ".\\results\\"+string_i+".txt";
std::ofstream outfile(file_dir);
// Here is the part where I am filling the .txt with some data
outfile << i << " some " << i << " constant " << i << " text " << i << " . . . "
<< i << " --more text-- " << i << " --even more-- " << i;
i++;
}
}
И теперь все (создание файлов .txt и заполнение их короткими данными) выполняется в течение ... ~37 секунд. Это огромная разница. И это всего 10 000 файлов.
Вопрос 2: Можно что-нибудь здесь оптимизировать? Возможно, существует какая-то альтернатива, которая быстрее заполняла бы файлы .txt. Или, может быть, я забыл о чем-то очень очевидном, что замедляет весь процесс?
Или, может быть, я немного преувеличиваю и секунды ~37 кажутся нормальными и оптимизированными?
Спасибо, что поделились своими мыслями!
Да, запись в файлы стоит дорого, особенно. когда вам нужна высокая пропускная способность. Не удивительно разница на порядок при записи чего-либо в файлы.
Также можно попробовать просто вывести outfile << 'a'? Если вы получите сумасшедшие более высокие числа, чем ничего не написав, я подозреваю, что виновата производительность файловой системы.
Я предполагаю, что это происходит с максимальной скоростью, с которой диск может справиться. Скорее всего, это замедляет только диск. В первом тесте нужно только сменить каталог в одном месте на диске. Во втором он должен посетить каждый файл на диске, чтобы поместить туда информацию.
@Asu outfile << 'a'; создает файлы 10000 .txt за секунды 4.70.
Попробуйте записать через неформатированные функции ввода, такие как 'std :: ostream :: write`, и измерить их производительность (убедитесь, что вы записали такое же количество байтов). Если это значительно быстрее, ваша виноватая - форматирование, если то же самое - платформа.
ostream::write дал еще худшие результаты D: + - 10%
Попробуйте записать на RAMdrive, чтобы увидеть, не ограничивает ли вас производительность механического диска.
Какую систему используете? Если вы используете MSVC++, вы используете реализацию, которая пыталась доказать, что потоки IOStream работают медленно. Конечно, это на самом деле не доказывало то, что намеревалось доказать, а скорее то, что одну реализацию можно сделать медленной. Для этой конкретной реализации использование std::ios_base::sync_with_stdio(false); в качестве первого элемента в main() оказало довольно большое влияние на производительность, когда я попробовал это (что, однако, было ~ 20 лет назад).
Связанный? stackoverflow.com/questions/12997131/…
Наличие тысяч файлов в одном каталоге приводит к медленному поиску и там.
Win10 x64, Code :: Blocks, G ++ с включенным флагом C++ 14.





Скорость создания файла зависит от оборудования, чем быстрее диск, тем быстрее вы можете создавать файлы.
Это очевидно из того факта, что Я запустил ваш код на процессоре ARM (Snapdragon 636, на мобильном телефоне, использующем termux), теперь мобильные телефоны имеют флэш-память, которая очень быстра, когда дело доходит до ввода-вывода. Итак, большую часть времени он работал менее 3 секунд, а иногда и 5 секунд. Это изменение ожидается, поскольку накопитель должен обрабатывать многопроцессорные операции чтения и записи. Вы сообщили, что для вашего оборудования потребовалось 47 секунд.Отсюда можно смело заключить, что скорость ввода-вывода в значительной степени зависит от оборудования.
Тем не менее я подумал о некоторой оптимизации вашего кода и использовал 2 разных подхода.
Использование аналога C для ввода-вывода
Использование C++, но запись фрагментом за один раз.
Я запустил симуляцию на своем телефоне. Я запускал его 50 раз, и вот результаты.
C был самым быстрым, занимая в среднем 2,73928 секунды, чтобы написать ваше слово в 10000 текстовых файлах, используя fprintf.
Написание на C++ всей строки за один раз заняло 2,7899 секунды. Я использовал sprintf, чтобы поместить полную строку в char [], а затем написал, используя оператор << в ofstream.
C++ Normal (ваш код) занял 2,8752 секунды
Это ожидаемое поведение, запись кусками выполняется быстрее. Прочтите ответ это, почему. Без сомнения, C был самым быстрым.
Вы можете заметить здесь, что разница не столь значительна, но если вы используете оборудование с медленным вводом-выводом, это становится значительным.
Вот код, который я использовал для моделирования. Вы можете проверить это самостоятельно, но не забудьте заменить аргумент std::system своими собственными командами (разные для Windows).
#include <iostream>
#include <time.h>
#include <string>
#include <fstream>
#include <stdio.h>
void CreateFiles()
{
int i = 1;
while (i <= 10000) {
// int filename = i;
std::string string_i = std::to_string(i);
std::string file_dir = "./results/"+string_i+".txt";
std::ofstream outfile(file_dir);
// Here is the part where I am filling the .txt with some data
outfile << i << " some " << i << " constant " << i << " text " << i << " . . . "
<< i << " --more text-- " << i << " --even more-- " << i;
i++;
}
}
void CreateFilesOneGo(){
int i = 1;
while(i<=10000){
std::string string_i = std::to_string(i);
std::string file_dir = "./results3/" + string_i + ".txt";
char buffer[256];
sprintf(buffer,"%d some %d constant %d text %d . . . %d --more text-- %d --even more-- %d",i,i,i,i,i,i,i);
std::ofstream outfile(file_dir);
outfile << buffer;
i++;
}
}
void CreateFilesFast(){
int i = 1;
while(i<=10000){
// int filename = i;
std::string string_i = std::to_string(i);
std::string file_dir = "./results2/"+string_i+".txt";
FILE *f = fopen(file_dir.c_str(), "w");
fprintf(f,"%d some %d constant %d text %d . . . %d --more text-- %d --even more-- %d",i,i,i,i,i,i,i);
fclose(f);
i++;
}
}
int main()
{
double normal = 0, one_go = 0, c = 0;
for (int u=0;u<50;u++){
std::system("mkdir results results2 results3");
clock_t tStart1 = clock();
CreateFiles();
//printf("\nNormal : How long it took to make files: %.2fs\n", (double)(clock() - tStart1)/CLOCKS_PER_SEC);
normal+=(double)(clock() - tStart1)/CLOCKS_PER_SEC;
tStart1 = clock();
CreateFilesFast();
//printf("\nIn C : How long it took to make files: %.2fs\n", (double)(clock() - tStart1)/CLOCKS_PER_SEC);
c+=(double)(clock() - tStart1)/CLOCKS_PER_SEC;
tStart1 = clock();
CreateFilesOneGo();
//printf("\nOne Go : How long it took to make files: %.2fs\n", (double)(clock() - tStart1)/CLOCKS_PER_SEC);
one_go+=(double)(clock() - tStart1)/CLOCKS_PER_SEC;
std::system("rm -rf results results2 results3");
std::cout<<"Completed "<<u+1<<"\n";
}
std::cout<<"C on average took : "<<c/50<<"\n";
std::cout<<"Normal on average took : "<<normal/50<<"\n";
std::cout<<"One Go C++ took : "<<one_go/50<<"\n";
return 0;
}
Также в качестве компилятора я использовал clang-7.0.
Если у вас есть другой подход, дайте мне знать, я его тоже протестирую. Если вы обнаружите ошибку, дайте мне знать, я исправлю ее как можно скорее.
Обратите внимание, что это также зависит от компилятора, Linux / gcc предоставляет по умолчанию IO_BUFSIZ (я считаю, что в настоящее время переименован в LIO_BUFSIZE) байтов 8192, в то время как Windows VS предоставляет только 512. Таким образом, «увеличение» до фиксированного 4096, как указано в связанном ответе, фактически сократит размер буфера ввода-вывода по умолчанию в Linux вдвое. (молодцы по тестированию и отчетности)
Ничего нового, потоки io не очень быстрые в C++. Вам следует попробовать аналог C, если ваша единственная цель - производительность. Также посмотрите {fmt}, AFAIK он может работать с потоками напрямую.