Arhn - архитектура программирования

StreamWriter: (Write+Flush)Async кажется намного медленнее, чем синхронные варианты

Я пытался найти узкое место ввода-вывода в своем классе и неожиданно заметил, что sw.Write("m"); sw.Flush() может быть на 20000 быстрее, чем await sw.WriteAsync("m"); Await sw.FlushAsync(); при записи 1000000 сообщений в файл. А случайно никто не знает почему? Могу поспорить, что конструктор StreamWriter, принимающий String, не параметризует поток для использования async.

Приведенный ниже код можно запустить из интерактивного C#. Да, это не лучшее место для измерения скорости, но оно все равно покажет, в чем дело:

var sr = new StreamWriter("G:\\file.file");
var N = 1000;
var sw = new Stopwatch();
sw.Start();

for (var i = 0; i < N; ++i)
{
    sr.Write("m"); // or await sr.WriteAsync("m");
    sr.Flush(); // or await sr.FlushAsync("m");
}

sw.Stop();
Console.WriteLine("Completed " + N
    + " iterations in " + sw.ElapsedMilliseconds + " milliseconds.");

sr.Close();

Запущенный на моем домашнем ПК из C# Interactive, вывод

Выполнено 1000 итераций за 1 миллисекунду.

для синхронного кода и

Выполнено 1000 итераций за 43383 миллисекунды.

для асинхронного.

Обновление: Также я заметил, что программа тормозит внутри FlushAsync. WriteAsync работает почти с той же скоростью, что и синхронная версия.

Все комментарии приветствуются.

Обновление 2*. Как упомянул @Cory Nelson в комментариях к своему ответу, FileStream.FlushAsync — это поддельный async, реализованный с помощью Task.Factory.StartNew, поэтому он не добавляет ничего полезного, кроме накладных расходов. При работе с короткими сообщениями накладные расходы становятся достаточно большими по сравнению с выполняемой работой, что замедляет выполнение.


  • Возможно, см. этот ответ. Кроме того, конечно, вы могли просто подождать два часа, чтобы сформировать полный пост? 31.01.2017
  • @Glorin Oakenfoot спасибо за ссылку. Да, мой плохой, но я волновался, что я, вероятно, могу забыть это :-( 31.01.2017
  • Я не знаю, зачем кому-то использовать метод асинхронной записи. Существует очень небольшая разница между синхронной записью и асинхронной записью. Синхронная запись происходит так быстро, что переход на асинхронный не оправдывает себя. 31.01.2017
  • @GlorinOakenfoot добавил код 31.01.2017
  • @jdweng да, я уже думаю о переходе на синхронную запись, если не решу эту проблему. 31.01.2017

Ответы:


1

StreamWriter при указании пути к файлу не открывает базовый поток в асинхронном режиме. Вероятно, это способствует снижению производительности. Если вы собираетесь использовать его для асинхронности, вы должны открыть свой собственный Stream:

Stream s = new FileStream("G:\\file.file", FileMode.Create, FileAccess.Write,
                          FileShare.None, 4096,
                          FileOptions.Asynchronous | FileOptions.SequentialScan);
StreamWriter sr = new StreamWriter(s);

Следует также отметить, что ваш тест, похоже, не отражает реальное использование. Вы действительно пишете односимвольные строки и сбрасываете после каждой?

Async имеет определенный фиксированный объем памяти и накладные расходы GC, и с такими недолговечными операциями — особенно с учетом того, что StreamWriter.WriteAsync в настоящее время не оптимизирован для небольших записей — вы обречены увидеть гораздо больше накладных расходов, чем более распространенное использование.

31.01.2017
  • Я пытался создать Stream вручную, но он все еще намного медленнее, чем синхронная версия. Нет, я не пишу строки из одного символа, а пишу короткие сообщения журнала. Кроме того, для меня не так важны накладные расходы памяти/GC, потому что другие конструкции с асинхронными операциями вызываются несколько миллионов раз в секунду, и все в порядке. 01.02.2017
  • Также я заметил, что настоящая проблема внутри FlushAsync. WriteAsync работает примерно с той же скоростью, что и синхронная версия. 01.02.2017
  • FlushAsync на FileStream, к сожалению, реализован с поддельной асинхронностью. Я ожидал, что он будет работать не очень хорошо. 01.02.2017
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..