Haskell 高效地创建严格的bytestring

Haskell 高效地创建严格的bytestring,haskell,Haskell,最近,在我的项目上运行了基准测试之后,我发现直接构建严格的bytestring可能比构建器的构建快一个数量级 例如,使用生成器的编码器实现: encoder :: Int64 -> Data.ByteString.ByteString encoder = Data.ByteString.Lazy.toStrict . Data.ByteString.Builder.toLazyByteString . Data.ByteString.Builder.int64BE 性能比直接

最近,在我的项目上运行了基准测试之后,我发现直接构建严格的bytestring可能比构建器的构建快一个数量级

例如,使用生成器的编码器实现:

encoder :: Int64 -> Data.ByteString.ByteString
encoder =
  Data.ByteString.Lazy.toStrict .
  Data.ByteString.Builder.toLazyByteString .
  Data.ByteString.Builder.int64BE
性能比直接构造bytestring的性能差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)
所以我的问题有两个方面:

  • 为什么不能通过testring将
    Builder
    直接转换为strict
    ?这很烦人,因为我经常需要导入
    数据.ByteString.Lazy
    来使用它的
    toStrict
    函数,因为
    数据.ByteString.Builder
    只公开
    toLazyByteString

  • 然而,上面提到的经历让我怀疑,这是否是有原因的。原因是我完全应用了一种不正确的用法模式。那么,这是否确实是错误的,是否有更好的选择?顺便说一句,我知道
    Data.ByteString.Builder.Prim
    ,但我怀疑在上述情况下使用它会有很大的不同


  • 构建器不是一个零成本的抽象,它针对大型惰性字符串进行了优化。来自建筑商:

    当前的实现针对4kb到32kb之间的平均块大小进行了调整

    在您的例子中,构建器分配整个4k块只是为了生成8个字节

    pack
    相比,pack计算所需的缓冲区大小,分配缓冲区大小,然后将其填充到循环中。效率低下的唯一原因是预先分配的8个
    Word8
    的列表。也许会更有效率


    使用builder构造小型严格的ByteString有时很方便,但有更好的方法。

    尝试使用
    数据.ByteString.builder.Extra中的
    toLazyByteStringWith
    来调整
    ByteString
    构造。这需要一个
    AllocationStrategy
    ,它允许您调整缓冲区大小和增长率。

    很有趣。对于我的日常工作,我假设builder->lazy ByteString->strict ByteString的方法只有在从大量短字符串构建大字符串时才有效。我通常打包。显示从数字到严格bs的转换。。。不知道它是否好。你能发布一些可以用来衡量绩效的代码吗?这看起来是一个有趣的问题,“postgresql二进制”项目有两个分支,它们使用上述两种不同的策略实现编码器。两者都有编码性能的基准。这里是,这里是。我认为问题在于
    Builder
    没有维护写入结果bytestring out所需的字节数,即使当您不进行惰性流传输时,这是静态已知的(O(1))或O(n)-但可能值得。您可以查看
    缓冲区生成器
    ,看看它是否满足您的需要。请参阅此处的讨论:您是否尝试过调整分配策略?使用builder构造一个小bytestring默认为分配一个大bytestring,然后分配一个正确长度的小bytestring。另外,
    blaze builder
    有一个
    writeToByteString
    ,这可能会使prim的使用效率大大提高(有一个将prim转换为写入的函数);如果您实现一个
    primFixedToByteString
    和/或一个
    primBoundedToBytestring
    @lpsmith,这可能会更好。我会考虑的,谢谢!你提到“更好的方法”。你的意思是什么?你有什么建议的库吗?@NikitaVolkov我的意思是通过一些特殊的方式来提高性能,比如
    unfovern
    。我不知道有什么特定的库可以让生活更轻松,我通常在性能不重要的时候使用bytestring builder。连接小的严格的bytestring怎么样?仅使用
    append
    和/或
    concat
    是否最有效?