2

我目前正在游戏网络代码中恭敬地使用bytestring和进行序列化和反序列化。attoparsec我最初被这些库所吸引,cereal因为它对bytestringBuilders 提供了非常细粒度的控制,包括有用的分配策略低级primatives 。我认为这将是一个不错的选择,因为它可以确保我能够更好地处理我在项目后期可能遇到的任何延迟/GC 问题。

虽然bytestring提供了许多常见数据类型的组合子,但在数据包字段中会遇到的常见数据类型(主要是在Data.Word和、和Data.Int中找到的类型),但当我在. 我错过了什么吗?我可以用提供的组合器模拟一些等效的东西吗?Word16Word16Int8attoparsec

如果是缺少功能的情况,添加此功能的通常方法是什么?我当然不是第一个需要用图书馆解码签名短裤的人。这个功能不存在有什么原因吗?是否有一个我应该补充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))

因为这是在内部做的事情cerealbinary也是我目前为获得此功能所做的事情,但最好不必使用临时的不安全函数来执行他们bytestring的APIcerealbinary已经提供的内容.

当大多数人需要在低延迟网络环境中处理Int64, Int32, Int16, Int8, Word64, Word32, 和attoparsec 时,他们会怎么做?Word16

(NEWBIE NOTE)这里有一个可能很幼稚的假设。我隐含地假设cereal处理网络数据包的速度并不比 和 中的实现bytestringattoparsec。这个假设起源于观看有关 binary-serialise-cbor 的一些谈话,这些谈话指出相当大量的分配发生在cerealbinary由于他们在缓冲区中编码和解码二进制数据的延续方法。我正在处理网络数据包,这些数据包通常可以以一种非常简单和无状态的方式进行编码和解码,其中偶尔出现的字段的编码/解码子例程取决于先前看到的字段的值。也许我需要在这里进行现实检查并且我使用了错误的工具来完成这项工作?也许在这个高层次上我真的没有什么可以做的来改善我的处境?假设“不要过早优化”在这种情况下不适用。

4

1 回答 1

1

您应该更详细地解释您对数据包所做的工作。大多数网络数据包处理不需要回溯,因此 attoparsec 有点矫枉过正。此外, attoparsec(以及二进制和谷物)要求您访问数据包的每个字节。然而,大多数网络数据包中的字段位置都是固定的。因此,一旦您检查了标头以确定您拥有哪种数据包,您就可以“随机访问”这些字段。

我认为您可以实现(接近)零分配实现——只需像在 C 中那样编写算法:将数据包数据加载到可变的未装箱向量中;保持当前数据包开头的偏移量;如果您的缓冲区中没有完整的数据包,请将您拥有的内容移动到向量的顶部,并用新的数据包数据填充其余部分。

于 2016-06-19T05:02:30.080 回答