Использование StreamWriter: что быстрее записывает одну большую строку или много меньших фрагментов?

#c# #filestream #streamwriter

#c# #файловый поток #streamwriter

Вопрос:

Я создаю выходной файл HTML на C #, хотя скорость работы с файлами размером 60 Мб кажется невероятно высокой. Создание файла занимает 20 минут, что является очень медленным процессом. Ранее около 35 Мб он создавался за 5 секунд, поэтому я не уверен, что здесь вызывает задержку.

Сначала я бы использовал эти строки, чтобы начать генерировать отчет:

   public static void GenerateHtmlReport()
        {
            GenerateFinalResults();
            HtmlFileName ??= "Report-"   $"{DateTime.Now:dd_MMM_yyyy-[HH_mm]}"   ".html";
            var fileName = Path.Combine(GetRootFolder(), HtmlFileName);
            using var fs = new FileStream(fileName, FileMode.Create);
            using var w = new StreamWriter(fs, Encoding.UTF8);
            w.WriteLine(RenderHtml.ContructReportHeader(User));
            RenderHtml.ConstructHtmlBody(Results, w);
            w.WriteLine(RenderHtml.ConstructFullSummaryReport(Results));
            w.WriteLine(RenderHtml.ContructDashboard(Results, ResultStart));
        }
 

Если я записываю в файл полную строку, то это занимает довольно много времени, тем не менее запись ее по частям, на мой взгляд, не намного полезнее.

Хотя это приводит меня к двум вопросам

  1. Какой процесс был бы быстрее — запись целой строки или небольших фрагментов?
  2. есть ли другой метод записи файлов, который я должен использовать для ускорения производительности?

С уважением,

Комментарии:

1. Почему бы вам не сравнить это? Хотя я сомневаюсь, что вы заметите какую-либо разницу, поскольку StreamWriter использует внутренний буфер 1K, а FileStream по умолчанию использует буфер 4K. Оба размера могут быть изменены

2. Что вы подразумеваете под этим тестом?

3. Это означает, что фактически измеряется время, затраченное в каждом случае. Если вам нужно 20 минут для 60 МБ, проблема не имеет ничего общего с файлами. Я бы предположил, что приложение использует неэффективные операции со строками, создавая множество временных строк, которые необходимо собирать для мусора. Даже тогда от 5 секунд до 20 минут — это много.

4. Вместо того, чтобы угадывать, профилируйте свое приложение. В самой Visual Studio вы можете проверить использование процессора и памяти приложением во время его работы. Если вы видите постоянно увеличивающееся использование памяти или изображение бензопилы, проблема действительно связана с памятью и сборкой мусора. Строки неизменяемы, поэтому любая операция модификации строки создает новую строку, которую в конечном итоге необходимо скопировать. Добавление большого количества элементов в список<T> без указания емкости также приводит к перераспределению

5. Я подозреваю, что если вы перепишете свой код, чтобы можно было переходить через функции, вы поймете, что задержка возникает из RenderHtml.ContructReportHeader(User) , RenderHtml.ConstructFullSummaryReport(Results) а RenderHtml.ContructDashboard(Results, ResultStart) не из WriteLine . Если какой-либо из этих методов генерирует что-то большее, чем одну короткую строку, он должен записывать выходные данные непосредственно в writer вместо буферизации 60 МБ текста в памяти, чтобы записать его в конце

Ответ №1:

Ответ действительно является StringBuilder . Внесение изменений во все части кода вместо использования (конкатенация) Я подал в суд на StringBuilder.Append() и вернул его обратно в виде строки. Теперь отчет создается менее чем за 5 секунд вместо 22 минут. Так что это огромное улучшение.

Комментарии:

1. Не совсем. Нет необходимости хранить 60 МБ текста в памяти (в StringBuilder). Вместо stringBuilder.Append этого может быть записано непосредственно в поток с помощью streamWriter.Write .

2. Мы бы не хранили все это в памяти, а логическими блоками, и на следующей итерации оно снова стало бы пустым. Хотя. да, мы могли бы вместо этого записать все в файл, но это работает для меня.