2015-10-18 99 views
12

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

例如,编码器实现,它采用的助洗剂:

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) 

所以我的问题是两方面的:

  1. 瓦y是否没有直接从Builder转换为严格ByteString?这很烦人,因为我经常必须导入Data.ByteString.Lazy只是为了使用toStrict函数,因为Data.ByteString.Builder只公开toLazyByteString

  2. 但是,上述经验让我怀疑,如果它不是有原因的。原因是我完全应用了不正确的使用模式。那么,这确实是不正确的,是否有更好的选择?顺便说一句,我知道Data.ByteString.Builder.Prim,但我怀疑在上述情况下使用它会产生很大的差异。

+0

有趣。对于我的日常工作,我假设builder - > lazy ByteString - > strict Bytestring的方式在从大量短字符串中构建一个大字符串时只会付出代价。我通常会打包。显示从数字转换为严格的bs ...不知道它是否好。你可以发布一些可用于衡量性能的代码吗?这看起来像一个有趣的问题。 – dsign

+0

“postgresql-binary”项目有两个分支,它们使用两种不同的策略实现编码器。两者都具有编码性能的基准。这是[一棵树,其中的编码器是通过直接的'ByteString'构造实现的](https://github.com/nikita-volkov/postgresql-binary/tree/911a32110cfd618e2f7d377f4acc4c8f593f9acc),这里是[围绕'Builder'旋转的那个] (https://github.com/nikita-volkov/postgresql-binary/tree/2fb6954968763621cbbdb8ba8505434ec2961b9e)。 –

+1

我觉得麻烦的是'Builder'不保持写出结果字节串所需的字节数,尽管当你没有做懒惰流时,这是静态已知的(O(1))或O( N) - 丁大概价值 - 它。你可以看看'buffer-builder',看看它是否满足你的需求。请参阅此处的讨论:https://github.com/chadaustin/buffer-builder/issues/7 – jberryman

回答

7

构建器不是一个零成本的抽象,它针对大型惰性字符串进行了优化。从建设者docs

目前的实现是4KB和32KB

之间进行调整,平均块大小根据你的情况,建设者分配整个4K块只产生8个字节。

pack比较,它计算必要的缓冲区大小,分配它,然后在循环中填充它。低效率的唯一来源是预先分配的8 Word8的清单。可能unfoldrN会更有效率。

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

+0

谢谢!你提到“更好的方法”。你意味着什么?有没有你会建议的图书馆? –

+0

@NikitaVolkov我认为更好的表现特别的方式,比如'unfoldrN'。我不知道任何使生活更轻松的特定库,并且当性能不重要时,我通常使用bytestring构建器。 – Yuras

+0

连接小严格字节串怎么样?使用'append'和/或'concat'最有效吗? –

3

尝试使用toLazyByteStringWith来自Data.ByteString.Builder.Extra来调整您的ByteString构造。这需要AllocationStrategy,它允许您调整缓冲区大小和增长率。