Обложка канала

.NET Разработчик

Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин

.NET Разработчик

4 года назад
Открыть в
День 1264. #ЗаметкиНаПолях Используем 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. Окончание следует… Источник: code-maze.com/csharp-…formance