我目前正在使用bytestring
和attoparsec
在游戏网络代码中进行序列化和反序列化。我最初被cereal
使用这些库所吸引,因为bytestring
对构建器提供了相当精细的控制,包括有用的alloctation strategies和low-level primatives。我认为这将是一个不错的选择,因为它可以确保我能够更好地处理我可能在项目后期遇到的任何延迟/ GC问题。
虽然bytestring
为常见数据类型提供了许多组合器,但会遇到数据包字段(主要是Data.Word
和Data.Int
中的类型,如Word16
,{{ 1}}和Word16
),当我无法在Int8
找到任何互补的组合子时,我感到很失望。我错过了什么吗?我可以用提供的组合器模拟一些东西吗?
如果缺少功能,那么添加此功能的常用方法是什么?我当然不是第一个需要用库解码签名短裤的人。这个功能是否存在的原因是否存在?是否有一个共同的图书馆,我应该补充attoparsec
我不知道的?或者我应该这样做:
attoparsec
因为这是import Data.Bits
import qualified Data.ByteString as B
import qualified Data.ByteString.Unsafe as B
import qualified Data.Attoparsec.ByteString as Decode
import Data.Int
decodeInt16BE :: Decode.Parser Int16
decodeInt16BE = do
bs <- Decode.take 2
return $! (fromIntegral (bs `B.unsafeIndex` 0) `shiftL` 8) .|.
(fromIntegral (bs `B.unsafeIndex` 1) 1))
和cereal
内部所做的事情以及我目前正在做的目标,但是不必使用ad hoc会很好不安全的函数,以便执行其API中已提供的binary
,bytestring
和cereal
。
大多数人在需要解决binary
,Int64
,Int32
,Int16
,Int8
,{{1}时需要做什么? }和Word64
在低延迟网络环境中使用attoparsec?
(NEWBIE NOTE)这里的假设可能是天真的。我隐含地假设Word32
处理网络数据包的速度不比Word16
和cereal
中的实现快。这个假设源于观察talks coming out on binary-serialise-cbor中的一些{{3}},这些分配指向bytestring
和attoparsec
中发生的相当大量的分配,因为它们继续在缓冲区中编码和解码二进制数据。我处理的网络数据包通常可以以非常简单和无状态的方式进行编码和解码,偶尔的字段的编码/解码子程序依赖于先前看到的字段的值。也许我需要在这里进行现实检查并使用错误的工具来完成工作?也许在这个高层次上我真的无法改善我的处境?假设没有过早地优化&#34;在这种情况下不适用。
答案 0 :(得分:1)
您应该更详细地解释您对数据包的处理方式。大多数网络数据包处理不需要回溯,因此attoparsec有点矫枉过正。此外,attoparsec(以及二进制和谷物)要求您访问数据包的每个字节。但是,大多数网络数据包中的字段位置都是固定的偏移量。因此,一旦检查了标题,就可以“随机访问”字段,以确定您拥有的数据包类型。
我认为你可以实现(接近)零分配实现 - 只需像在C中那样编写算法:将数据包数据加载到可变的未分箱矢量中;保持当前数据包开始的偏移量;如果你的缓冲区中没有完整的数据包,请将你拥有的数据移到矢量顶部,然后用新的数据包数据填写其余部分。