Я пишу высокопроизводительный парсер для потока с разделителями-запятыми (сети). Моя цель — разобрать и преобразовать напрямую из двоичных файлов в примитивы dotnet. Основываясь на моем тестировании до сих пор, производительность Span невероятна, но с этим типом сложно работать из-за ограничений, присущих структурам ref. Я столкнулся с препятствием, пытаясь найти эффективный способ хранения констант Span (запятая, новая строка и т. д.), используемых в моем приложении. Единственное решение, которое существует, чтобы хранить их как byte и преобразовывать их в тела классов методов... или жестко кодировать Span<byte> delimiter = Encoding.UTF8.GetBytes("\r\n") в тело каждого метода.
Я хотел бы добиться следующего, но выдает ошибку: «CS8345 Поле или автоматически реализуемое свойство не может иметь тип «Span», если только оно не является членом экземпляра структуры ref.
public class Parser
{
Span<byte> NewLine = new byte[]{ (byte)'\n' };
}
Должен быть лучший способ! Пожалуйста помоги!
Вы можете создать ReadOnlySpan<byte> с литералом UTF-8 в .NET 7:
class Consts
{
public static ReadOnlySpan<byte> Delim => "\n"u8;
}
Или используйте Memory/ReadOnlyMemory:
public class Consts
{
public static ReadOnlyMemory<int> Type { get; } = new []{1};
}
И использование:
ReadOnlySpan<int> span = Consts.Type.Span;
Или украсьте вышеупомянутый подход свойством метода/выражения:
class Consts
{
private static readonly byte[] _delim = { (byte)'\n' };
public static ReadOnlySpan<byte> Delim => _delim;
}
Демо
@AdamCohen, посмотри мой комментарий.
Вы сталкиваетесь с проблемами, потому что ref structs, как и Span<T>, являются специальными типами данных с ограничениями, которые гарантируют, что они не могут выйти из стека. Classes — это ссылочные типы, которые живут в куче. Таким образом, если бы Span был членом класса, это нарушило бы правило «только стек». Тем не менее, статические свойства, которые реализованы (не автоматически реализуются, например, { get; set;}), разрешены и кажутся решением, которое вы ищете. См. следующий пример...
public class Parser
{
static Span<byte> NewLine => { (byte)'\n' };
static ReadOnlySpan<byte> Comma => { (byte)',' };
private static Span<byte> TraditionSyntax
{
get
{
return new[] {(byte)'\n' };
}
}
}
Обратите внимание, что синтаксис "string"u8.Array() — это литерал, который преобразует строку непосредственно в UTF8, как если бы вы вызывали кодировщик так, как указано в вашем примере. Тем не менее, обязательно проверьте литерал, чтобы убедиться, что он дает то, что вы ожидаете. Это не всегда соответствует Encoding.UTF8.
Не отвлекайтесь на тело метода (геттер свойств). Существует оптимизация компилятора, которая позволяет избежать выделения памяти при использовании (byte).
Это вызовет тело выражения для каждого вызова, полностью отвечающее цели, т. е. ToArray будет вызываться каждый раз.
Неа. Для этого есть оптимизация компилятора. См. выше.
Я исправил использование (byte) '\n' в одном из примеров, чтобы избежать путаницы. Надеюсь это поможет.
@acoder Я не вижу никаких @sharplab
@acoder и память распределяются в соответствии с GC.GetTotalAllocatedBytes - Demo
«Обратите внимание, что синтаксис «string» u8.Array () является литералом, который преобразует строку непосредственно в UTF8» - не могли бы вы поделиться доказательством утверждения.
public static ReadOnlySpan<byte> NewLine => "\n"u8;
буквально.
@GuruStron - в теле моего метода TraditionalSyntax используется версия, оптимизированная для компилятора (поскольку вы обновили свой ответ до реплицированного). Два других примера просто иллюстрируют, как использовать ярлык Encoder.UTF8.GetBytes(). И все вышеперечисленное должно быть оптимизировано в .Net7 Roslyn, хотя я не уверен на 100%, что он был выпущен.
@AdamCohen «И все вышеперечисленное должно быть оптимизировано с помощью .Net7 Roslyn» - на основе декомпиляции и моих тестов - это не так. Еще раз - не могли бы вы поделиться документами?
Похоже, это Net8.0. Предполагалось, что они устранят необходимость в .ToArray()...learn.microsoft.com/en-us/dotnet/csharp/language-reference/… , и на github есть обсуждения и множество PR. Нет времени на поиски, но я уверен, что вы можете найти через Google. Над ним работают Туб и еще несколько лучших парней. Надеюсь это поможет
См. выше, как это сделать напрямую с помощью Span<T>.