Я пишу высокопроизводительный парсер для потока с разделителями-запятыми (сети). Моя цель — разобрать и преобразовать напрямую из двоичных файлов в примитивы 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>.