Haskell 高效地创建严格的bytestring
最近,在我的项目上运行了基准测试之后,我发现直接构建严格的bytestring可能比构建器的构建快一个数量级 例如,使用生成器的编码器实现:Haskell 高效地创建严格的bytestring,haskell,Haskell,最近,在我的项目上运行了基准测试之后,我发现直接构建严格的bytestring可能比构建器的构建快一个数量级 例如,使用生成器的编码器实现: encoder :: Int64 -> Data.ByteString.ByteString encoder = Data.ByteString.Lazy.toStrict . Data.ByteString.Builder.toLazyByteString . Data.ByteString.Builder.int64BE 性能比直接
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)
所以我的问题有两个方面:
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
是否最有效?