Эффективная байтовая очередь С# для анализа потока байтов для двоичных пакетов сообщений

Я пытаюсь заменить то, что я обычно реализую как круговой буфер+. Функция очереди - буферизация входящих байтов (например, из последовательного порта или другого потока данных), в то время как парсер анализирует байты в очереди и обнаруживает и извлекает пакеты сообщений.

Критерии:

  • может расти (т.е. не фиксированный)
  • = 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 для ввода/выгрузки данных