Используем Span Для Производительности. Начало
Сегодня рассмотрим
Span в C#, как он реализован и как мы можем использовать его для повышения производительности.Span<T> — это типобезопасное и безопасное по памяти представление непрерывной области памяти. Span<T> реализован как ref-структурa (подробнее о ref-структурах), которая содержит ссылку на объект T и длину для чтения. Т.е. Span в C# всегда будет размещаться на стеке, а не в куче. Рассмотрим упрощённую реализацию Span<T>:public readonly ref struct Span<T>Использование
{
private readonly ref T _pointer;
private readonly int _length;
}
Span<T> повышает производительность за счёт размещения на стеке, т.к. сборка мусора не тормозит выполнение приложения. Операции со Span<T> аналогичны операциям с массивами: индексация в Span не требует вычислений для определения адреса памяти.Другой реализацией
Span является ReadOnlySpan<T>. Его отличие от Span в том, что индексатор возвращает ссылку на T только для чтения. Это позволяет использовать ReadOnlySpan<T> для представления неизменяемых типов данных, таких как string.Span может использовать типы значений, такие как int, byte, ref struct, bool и enum. Span не может использовать такие типы, как object, dynamic или интерфейсы.Ограничения
Реализация
Span ограничивает его использование в коде. Объекты ссылочного типа размещаются в куче, поэтому мы не можем использовать Span в качестве полей в ссылочных типах. Также ref-структуры не могут быть упакованы, и Span нельзя использовать в лямбда-выражениях и асинхронном коде с await, а также с yield. Кроме того, т.к. мы выделяем память в стеке, мы должны помнить, что памяти в стеке меньше, чем в куче.Span-подобный класс можно использовать в асинхронном коде. Это классы
Memory<T> и ReadOnlyMemory<T>.Примеры
Мы можем использовать Span для работы с массивами и другими типами коллекций:
int[] arr = new[] { 0, 1, 2, 3 };
Span<int> intSpan = arr;
var otherSpan = arr.AsSpan();
C# предлагает неявное приведение от T[] к Span<T>, но мы также можем вызвать AsSpan() для массивов. Как ReadOnlySpan<T>, так и Span<T> предлагают знакомые по работе с массивами функции, не выделяющие дополнительную память.Теперь рассмотрим на аналогичный пример с
List<T>:List<int> intList = new() { 0, 1, 2, 3 };
var listSpan = CollectionsMarshal.AsSpan(intList);
Использовать Span с коллекцией не так просто, как с массивами. В этом случае мы должны использовать метод CollectionMarshal.AsSpan(), чтобы получить коллекцию в виде Span. Для этого нужно импортировать пространство имён System.Runtime.InteropServices.Окончание следует…
Источник: https://code-maze.com/csharp-span-to-improve-application-performance/