Эффективная байтовая очередь С# для анализа потока байтов для двоичных пакетов сообщений
Я пытаюсь заменить то, что я обычно реализую как круговой буфер+. Функция очереди - буферизация входящих байтов (например, из последовательного порта или другого потока данных), в то время как парсер анализирует байты в очереди и обнаруживает и извлекает пакеты сообщений.
Критерии:
- может расти (т.е. не фиксированный)
-
= 1 байт может быть выставлен в очередь за раз
-
= 1 байт может быть выгружен за раз
- эффективный
Я искушаюсь просто использовать
System.Collections.Generic.Queue<byte>
... но я не уверен, что это самый эффективный тип для использования. Любые предложения?
Есть ли более разумные способы делать то, что я пытаюсь сделать? (Например, интересные предложения здесь)
Спасибо за ваши предложения и ввод.
Prembo.
Ответы
Ответ 1
Queue<byte>
поддерживается byte[]
, но вы бы видели лучшую производительность при копировании в/из базового буфера с помощью Array.Copy
, а не в циклическом использовании методов Enqueue/Dequeue. Поэтому, если Queue<byte>
не дает вам требуемой производительности, тогда вы можете реализовать свой собственный класс очереди, который предоставляет методы QueueMultiple и DequeueMultiple.
Ответ 2
Ну, Queue<byte>
будет эффективным с точки зрения памяти. Это будет в основном byte[]
за кулисами. Это может быть немного неудобно работать, если вы хотите удалить или выложить целые куски за один раз. Каждая операция должна быть амортизирована O (1) для одного байта, что приводит к тому, что O (n) устанавливает или выгружает фрагмент размера n... но коэффициент масштабирования будет выше, чем (скажем) копии буферного блока.
Ответ 3
В зависимости от того, как поступают входящие байты и как парсер проверяет их, вы можете рассмотреть Queue<byte[]>
.
Ответ 4
Я знаю, что я не буду полезен, но вы можете написать свою собственную.
Теоретическая часть:
Очередь должна быть в byte[]
и 2 индексах, 1 для головы и 1 для хвоста
0 n
|----------------------------------------------------|
| |
head tail
Каждый раз, когда вам нужно добавить k
байты, вы перемещаете хвост k
единиц слева и помещаете в новое пространство созданные данные там.
0 n
|-------------------------------new data-------------|
| | |
head new tail old tail
Каждый раз, когда вам нужно вставлять k
байты, вы перемещаете голову k
единиц слева и берете данные из потерянного пространства.
0 n
|-------new data-------------------------------------|
| | |
new head head tail
В случае столкновения головы и хвоста вам нужно удвоить размер контейнера и скопировать каждую половину на новую.
Имейте в виду: если вы добавите 1234
, а затем нажмите 2 буквы, вы получите 34
(Я не знаю, следует ли отмечать это сообщение как сообщество wiki)
Ответ 5
Здесь эффективная реализация буфера, который я написал некоторое время назад:
- Resizeable: позволяет помещать в очередь данные и исключать исключение переполнения буфера;
- Эффективный: использует один буфер и операции Buffer.Copy для ввода/выгрузки данных