【问题标题】:Convert a Lazy ByteString to a strict ByteString将惰性字节字符串转换为严格字节字符串
【发布时间】:2011-12-10 13:15:58
【问题描述】:

我有一个接受lazy ByteString 的函数,我希望有strict ByteStrings 的返回列表(懒惰应该转移到输出的列表类型)。

import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
csVals :: L.ByteString -> [B.ByteString]

出于各种原因我想这样做,several lexing functions require strict ByteStrings,我可以保证上面csVals 的输出中输出的 strict ByteStrings 很小。

如果没有chunking 他们,我该如何“严格”ByteStrings?

更新0

我想要一个 Lazy ByteString,并制作一个包含所有数据的严格 ByteString

【问题讨论】:

  • toChunks 有什么问题?乍一看,它似乎保留了懒惰。
  • @Matt Joiner:也许你应该自己写一个词法分析,或者使用 DeepSeq 强制评估结果。
  • @Matt Joiner:同一个包中有一个 Lazy 版本:'Data.ByteString.Lex.Lazy.Double'。
  • @Matt Joiner:所以你想要指定大小的块?可能重复调用 splitAt?请注意,toChunks 生成严格的 ByteString 具有最大大小(可能最后一个除外)。
  • 这里有一个误解——惰性字节串 is 本质上只是一个块列表(即严格的字节串)。 toChunks 公开了该结构。要将列表全部放在一个严格的字节串中,除了concat . toChunks(或等效项)之外别无他法。在许多典型情况下,列表将只有一个元素——在这些情况下,concat . toChunks 也会相对有效。

标签: haskell lazy-evaluation strict bytestring chunking


【解决方案1】:

Data.ByteString.Lazy.Char8 现在具有 toStrict 和 fromStrict 函数。

【讨论】:

  • 这似乎本质上是 ocharles 答案的副本。
【解决方案2】:

您也可以使用blaze-builder 从惰性构建严格的 ByteString

toStrict :: BL.ByteString -> BS.ByteString
toStrict = toByteString . fromLazyByteString

必须有效。

【讨论】:

    【解决方案3】:

    bytestring 包现在导出一个 toStrict 函数:

    http://hackage.haskell.org/packages/archive/bytestring/0.10.2.0/doc/html/Data-ByteString-Lazy.html#v:toStrict

    这可能不是你想要的,但它肯定回答了这篇文章标题中的问题:)

    【讨论】:

    • 有什么线索是在哪个版本中添加的? Haskell平台2012.4(包括ghc 7.4)好像没有?
    【解决方案4】:

    就像@sclv 在上面的 cmets 中所说,惰性字节串只是严格字节串的列表。有两种方法可以将惰性 ByteString 转换为严格(来源:haskell mailing list discussion about adding toStrict function)- 来自以下电子邮件线程的相关代码:

    一、相关库:

    import qualified Data.ByteString               as B
    import qualified Data.ByteString.Internal      as BI
    import qualified Data.ByteString.Lazy          as BL
    import qualified Data.ByteString.Lazy.Internal as BLI
    import           Foreign.ForeignPtr
    import           Foreign.Ptr
    

    方法 1(与@sclv 相同):

    toStrict1 :: BL.ByteString -> B.ByteString
    toStrict1 = B.concat . BL.toChunks
    

    方法二:

    toStrict2 :: BL.ByteString -> B.ByteString
    toStrict2 BLI.Empty = B.empty
    toStrict2 (BLI.Chunk c BLI.Empty) = c
    toStrict2 lb = BI.unsafeCreate len $ go lb
      where
        len = BLI.foldlChunks (\l sb -> l + B.length sb) 0 lb
    
        go  BLI.Empty                   _   = return ()
        go (BLI.Chunk (BI.PS fp s l) r) ptr =
            withForeignPtr fp $ \p -> do
                BI.memcpy ptr (p `plusPtr` s) (fromIntegral l)
                go r (ptr `plusPtr` l)
    

    如果性能是一个问题,我建议查看上面的电子邮件线程。它也有标准基准。在这些基准测试中,toStrict2 比 toStrict1 快。

    【讨论】:

      【解决方案5】:

      如果有问题的惰性字节字符串

      toStrict = fromMaybe SB.empty . listToMaybe . toChunks
      

      toChunks 使每个块尽可能大(可能最后一个除外)。

      如果你的惰性字节字符串的大小大于比严格字节字符串的大小,那么这是不可能的:这正是惰性字节字符串的用途。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-10
        • 2012-04-26
        • 2022-01-18
        相关资源
        最近更新 更多