C # StreamReader вызывает 200 мс накладных расходов на чтение данных из источника

#c# #.net #service #streamreader

#c# #.net #Обслуживание #streamreader

Вопрос:

Существует проблема, из-за которой мы наблюдаем некоторые периодические накладные расходы 200 мс на чтение входного потока из устройства чтения потоков, когда в системе есть нагрузка. Мне интересно, видел ли это кто-нибудь еще и сделали ли они что-нибудь, чтобы это исправить?

Ниже приведен код:

 string requestBody;
var streamReaderTime = Stopwatch.StartNew();
using (var streamReader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
{
    var allLines = streamReader.ReadLines();
    var request = new StringBuilder();
    allLines.ForEach(line => request.Append(line));
    requestBody = request.ToString();
}
streamReaderTime.Stop();
  

Строка чтения выглядит следующим образом:

 public static IEnumerable<string> ReadLines(this StreamReader reader)
{
   while (!reader.EndOfStream)
   { 
     yield return reader.ReadLine();
   }
}
  

Примечание: использование ReadLines() или ReadToEnd() имеет очень небольшое значение, если таковое имеется.

Мы запускаем тесты производительности в одночасье, и мы видим следующее поведение только из графика streamReaderTime.

введите описание изображения здесь

Выполнение одного запроса занимает от 45 до 70 мс, но на скриншоте видно, что он добавляет фиксированное значение, а иногда и еще больший всплеск. Я видел это до того, как прошло около 1,5 секунд.

Если у кого-нибудь есть какие-либо решения / предложения, мы будем очень признательны.

Редактировать: у меня был ReadToEnd() вместо ReadLines(), и это избавило от StringBuilder, но это были все те же накладные расходы. Есть ли альтернатива StreamReader, просто для проверки? Это действительно похоже на затраты на сборку, поскольку наличие запроса в течение десяти секунд не влияет на это, но точно такой же запрос в секунду приведет к возникновению этих накладных расходов. Кроме того, я также не могу воспроизвести его локально, это происходит только в виртуальной среде.

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

1. Забыл добавить, средний размер полезной нагрузки составляет около 62,6 КБ. Размер полезной нагрузки, похоже, не оказывает никакого влияния.

2. Ваш код генерирует много мусора, хорошие шансы, что ваш секундомер измеряет накладные расходы на сбор мусора.

3. У меня был ReadToEnd() вместо ReadLines(), и это избавило от StringBuilder, но это были все те же накладные расходы. Есть ли альтернатива StreamReader? Это действительно похоже на затраты на сборку, поскольку наличие запроса в течение десяти секунд не влияет на это, но один запрос в секунду приведет к возникновению этих накладных расходов. Также я также не могу воспроизвести его локально. Я обновлю свой вопрос с этими деталями.

Ответ №1:

Эта проблема вообще не связана с приведенным выше кодом. Проблема связана с вызывающим абонентом. При вызове службы используется библиотека, которая прерывает соединения на ранней стадии, и эти накладные расходы — это повторное установление соединения.