blogs.msdn.microsoft.com

Дата: 2019-09-08

System.IO.Pipelines — это новая библиотека, упрощающая организацию кода в .NET. Трудно обеспечить высокую производительность и точность, если приходится иметь дело со сложным кодом. Задача System.IO.Pipelines — упростить код. Подробнее под катом!

Библиотека появилась в результате усилий команды разработчиков .NET Core, которые стремились сделать Kestrel одним из самых быстрых веб-серверов в отрасли. Она изначально задумывалась как часть реализации Kestrel, но превратилась в повторно используемый API, доступный в версии 2.1 в качестве BCL API первого класса (System.IO.Pipelines).

Какие проблемы она решает?

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

Какие сложности возникают сегодня?

Начнем с простой задачи. Нам необходимо написать TCP-сервер, который получает от клиента сообщения с разделителями строк ().

Сервер TCP с NetworkStream

ОТСТУПЛЕНИЕ: как и в любой задаче, требующей высокой производительности, каждый конкретный случай стоит рассматривать исходя из особенностей вашего приложения. Возможно, тратить ресурсы на использование различных подходов, о которых пойдет речь далее, не имеет смысла, если масштаб сетевого приложения не очень велик. Обычный код .NET перед использованием конвейеров выглядит примерно так:

// Process a single line from the buffer

см. sample1.cs на GitHub Вероятно, этот код будет работать при локальном тестировании, но он имеет ряд ошибок:

Это наиболее распространенные ошибки чтения потоковых данных. Чтобы их избежать, необходимо внести ряд изменений:

см. sample2.cs на GitHub Повторюсь: это могло бы сработать при локальном тестировании, но иногда встречаются строки длиной больше 1 Кб (1024 байта). Необходимо увеличить размер входного буфера до тех пор, пока не будет найдена новая строка. Кроме того, мы собираем буферы в массив при обработке длинных строк. Мы можем улучшить этот процесс с помощью ArrayPool, что позволит избежать повторного распределения буферов во время анализа длинных строк, поступающих от клиента.

// Calculate the amount of bytes remaining in the buffer// Double the buffer size and copy the previously buffered data into the new buffer// Return the old buffer to the pool// EOF// Keep track of the amount of buffered bytes// Look for a EOL in the buffered data// Calculate the length of the line based on the offset// Process the line// Move the bytesConsumed to skip past the line we consumed (including \\n)