最近,在对我的项目运行基准测试之后,我发现直接构造严格字节串的速度可能比涉及构建器的字节速度快一个数量级。
例如,使用构建器的编码器实现:
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/