Структуры Span<T> и Memory<T>
C# Cooking
Структуры Span<T> и Memory<T> действуют как низкоуровневые фасады для массива, строки или любого смежного блока управляемой либо неуправляемой памяти. Их главная цель – содействовать определенным видам микро-оптимизации. В частности, они помогают писать код с низким выделением памяти, в котором выделение управляемой памяти сводится к минимуму (сокращая нагрузку на сборщик мусора), и нет необходимости в дублировании кода для разных типов входных данных. Они также делают возможным нарезание – работу с порциями массива, строки или блока памяти без создания копии.
Структуры Span<T> и Memory<T> особенно полезны в “горячих” точках, критичных к производительности, таких как конвейер обработки ASP.NET Core или средство разбора JSON, которое обслуживает объектную базу данных
В случае если вы встретили такие типы в каком-то API-интерфейсе и не нуждаетесь в предлагаемом ими потенциальном выигрыше в плане производительности, тогда можете легко обойтись без них, как описано ниже.
- При вызове метода, который ожидает тип Span<T>, ReadonlySpan<T>, Memory<T> или ReadOnlyMemory<T>, передавайте взамен массив, т.е. Т[]. (Это работает благодаря неявным операциям преобразования.)
- Чтобы преобразовать промежуток/память в массив, вызывайте метод ТоАггау. А если Т является char, то метод ToString преобразует промежуток/память в строку.
В частности, структура Span<T> решает две задачи.
- Она предоставляет общий интерфейс, подобный массиву, для управляемых массивов, строк и поддерживаемой указателем памятью. В результате у вас появляется свобода в плане работы с выделенной в стеке и неуправляемой памятью, избегая сборки мусора, и отсутствует необходимость дублировать код или возиться с указателями.
- Она делает возможным “нарезание”: открытие доступа к многократно используемым подразделам промежутка, не создавая копии.
Структура Span<T> состоит всего лишь из двух полей – указателя и длины. По этой причине она может представлять только смежные блоки памяти. (Если вам нужно работать с несмежными блоками памяти, то имеется класс ReadOnlySequence<T>, служащий в качестве связного списка.)
Поскольку структура Span<T> способна быть оболочкой для памяти, выделенной в стеке, существуют ограничения, касающиеся того, как можно хранить либо передавать экземпляры (обусловленные отчасти тем, что Span<T> является ссылочной структурой). Структура Memory<T> действует как промежуток без таких ограничений, но не может быть оболочкой для памяти, выделенной в стеке. Структура Memory<Т> по-прежнему обеспечивает преимущество нарезания.
Каждая структура поставляется с эквивалентом, допускающим только чтение (ReadOnlySpan<T> и ReadOnlyMemory<T>). Помимо предотвращения неумышленного изменения аналоги, поддерживающие только чтение, дополнительно улучшают производительность, снабжая компилятор и исполняющую среду добавочной свободой в плане оптимизации. В самой платформе .NET (и в ASP.NET Core) указанные типы применяются для повышения эффективности ввода-вывода, взаимодействия с сетью, обработки строк и разбора данных JSON.
Способность структур Span<T> и Memory<T> выполнять нарезание массивов делает старый класс ArraySegment<T> избыточным. Для содействия в отказе от него предусмотрены неявные операции преобразования из ArraySegment<T> во все структуры промежутков/памяти, а также из Memory<T> и ReadOnlyMemory<T> в ArraySegment<T>.