问题 高效的C#字节队列,用于解析二进制消息包的字节流


我正在尝试替换我通常实现的循环缓冲区+。队列的功能是缓冲传入的字节(例如,来自串行端口或一些其他数据流),而解析器检查队列中的字节并检测和提取消息包。

标准:

  • 可以成长(即不固定大小)
  • = 1个字节可以一次排队

  • = 1个字节可以一次出列

  • 高效

我很想去使用它

System.Collections.Generic.Queue<byte>

...但我不确定这是否是最有效的类型。有什么建议么?

有没有更明智的方法来做我想做的事情? (例如,有趣的建议 这里

感谢您的建议和意见。

Prembo。


6017
2017-07-18 14:23


起源



答案:


Queue<byte> 有一个支持 byte[],但如果使用复制到底层缓冲区或从底层缓冲区复制,您会看到更好的性能 Array.Copy 而不是循环通过Enqueue / Dequeue方法。所以,就个人而言 Queue<byte> 如果没有为您提供所需的性能,那么您可以实现自己的队列类,该类提供QueueMultiple和DequeueMultiple方法。


2
2017-07-18 15:03





好, Queue<byte> 在记忆方面会很有效率。它基本上是一个 byte[] 在幕后。如果您想要一次将整个队列出列或排队,那么使用它可能会有点尴尬。每个操作应该针对单个字节分摊O(1),导致O(n)将大小为n的块排队或出列...但是缩放因子将高于(例如)缓冲块复制。


3
2017-07-18 14:44





根据接收传入字节的方式以及解析器如何检查它们,您可能会考虑a Queue<byte[]>


2
2017-07-18 19:58





我知道我没有帮助,但你可以自己写一个。
理论部分:
队列应该在 byte[] 和2个指数,1个用于头部,1个用于尾部

0 n
| ------------------------------------------------- --- |
               | |
              头尾

每次需要添加 k 你移动的字节尾巴 k 单位留下并在新空间中创建数据。

0 n
| -------------------------------新数据------------- |
               | | |
              头尾新尾巴

每次你需要弹出 k 你移动的字节 k 单位离开并从丢失的空间中获取数据。

0 n
| -------新数据------------------------------------- |
       | | |
   新头颅尾

如果头部和尾部发生碰撞,则需要将容器的大小加倍并将每一半复制到新容器。

请记住:如果你添加 1234 然后弹出2个字母,你会得到 34 

(我不知道是否应该将这篇文章标记为社区维基)


2
2017-07-18 20:35



通常人们不会将他们的答案标记为社区维基。如果问题是社区维基,那么答案也将是社区维基。 - Drew Noakes
我想我错过了什么社区维基。 - Dani


答案:


Queue<byte> 有一个支持 byte[],但如果使用复制到底层缓冲区或从底层缓冲区复制,您会看到更好的性能 Array.Copy 而不是循环通过Enqueue / Dequeue方法。所以,就个人而言 Queue<byte> 如果没有为您提供所需的性能,那么您可以实现自己的队列类,该类提供QueueMultiple和DequeueMultiple方法。


2
2017-07-18 15:03





好, Queue<byte> 在记忆方面会很有效率。它基本上是一个 byte[] 在幕后。如果您想要一次将整个队列出列或排队,那么使用它可能会有点尴尬。每个操作应该针对单个字节分摊O(1),导致O(n)将大小为n的块排队或出列...但是缩放因子将高于(例如)缓冲块复制。


3
2017-07-18 14:44





根据接收传入字节的方式以及解析器如何检查它们,您可能会考虑a Queue<byte[]>


2
2017-07-18 19:58





我知道我没有帮助,但你可以自己写一个。
理论部分:
队列应该在 byte[] 和2个指数,1个用于头部,1个用于尾部

0 n
| ------------------------------------------------- --- |
               | |
              头尾

每次需要添加 k 你移动的字节尾巴 k 单位留下并在新空间中创建数据。

0 n
| -------------------------------新数据------------- |
               | | |
              头尾新尾巴

每次你需要弹出 k 你移动的字节 k 单位离开并从丢失的空间中获取数据。

0 n
| -------新数据------------------------------------- |
       | | |
   新头颅尾

如果头部和尾部发生碰撞,则需要将容器的大小加倍并将每一半复制到新容器。

请记住:如果你添加 1234 然后弹出2个字母,你会得到 34 

(我不知道是否应该将这篇文章标记为社区维基)


2
2017-07-18 20:35



通常人们不会将他们的答案标记为社区维基。如果问题是社区维基,那么答案也将是社区维基。 - Drew Noakes
我想我错过了什么社区维基。 - Dani


这里的 有效的实施 我刚才写的缓冲区:

  • 调整大小:允许排队数据而不是抛出缓冲区溢出异常;
  • 高效:使用单个缓冲区和Buffer.Copy操作来排队/出列数据

1
2018-04-18 12:48