最近,在对我的项目运行基准测试之后,我发现直接构造严格字节串的速度可能比涉及构建器的字节速度快一个数量级。

例如,使用构建器的编码器实现:

encoder :: Int64 -> Data.ByteString.ByteString
encoder =
  Data.ByteString.Lazy.toStrict .
  Data.ByteString.Builder.toLazyByteString .
  Data.ByteString.Builder.int64BE

它的性能比直接构造字节字符串的性能差10倍,并具有进一步优化的几种可能性:
encoder :: Int64 -> Data.ByteString.ByteString
encoder =
  unpackIntBySize 8

unpackIntBySize :: (Bits a, Integral a) => Int -> a -> Data.ByteString.ByteString
unpackIntBySize n x =
  Data.ByteString.pack $ map f $ reverse [0..n - 1]
  where
    f s =
      fromIntegral $ shiftR x (8 * s)

所以我的问题有两个方面:
  • 为什么没有从Builder直接转换为严格的ByteString?这很烦人,因为我经常只为了使用Data.ByteString.Lazy函数就必须导入toStrict,因为Data.ByteString.Builder仅公开toLazyByteString
  • 但是,所提到的经历让我感到奇怪,是否由于某种原因而没有出现。原因是我完全使用了不正确的使用模式。那么,这确实是不正确的,还有更好的选择吗?顺便说一句,我知道Data.ByteString.Builder.Prim,但是我怀疑在上述情况下使用它会产生很大的不同。
  • 最佳答案

    Builder不是零成本的抽象,它针对大型惰性字符串进行了优化。从生成器docs:



    在您的情况下,构建器仅分配整个4k块以产生8个字节。

    pack进行比较,后者计算所需的缓冲区大小,对其进行分配,然后将其填充到循环中。效率低下的唯一原因是预先分配的8个Word8的列表。 unfoldrN 可能会更加有效。

    使用builder构造小的严格字节串有时会很方便,但是有更好的方法。

    关于haskell - 有效创建严格的ByteStrings,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33195628/

    10-12 12:34