Haskell中的内存有效字符串

时间:2012-02-22 16:14:25

标签: string haskell

通常推荐的Haskell字符串类型似乎是ByteString或Text。我经常使用大量短(英文单词大小)字符串,并且通常需要将它们存储在诸如Data.Map的查找表中。在许多情况下,我发现在这种情况下,字符串表可以占用比ByteStrings表更少的内存。 Word8的Unboxed Data.Vectors也比ByteStrings更紧凑。

当需要在Haskell中存储和比较大量小字符串时,最佳做法是什么?

下面我试图将一个特定问题的案例压缩成一个小例子:

import qualified Data.ByteString.Lazy.Char8 as S
import qualified Data.ByteString as Strict
import qualified Data.Map as Map
import qualified Data.Vector.Unboxed as U
import qualified Data.Serialize as Serialize
import Control.Monad.State

main =   putStr 
  . unlines . map show . flip evalState (0,Map.empty) 
  . mapM toInt 
  . S.words
  =<<
  S.getContents


toInt x = do  
  let x' =   
          U.fromList . Strict.unpack .  -- Comment this line to increase memory usage
           Serialize.encode $ x  
  (i,t) <- get
  case Map.lookup x' t of
    Just j -> return j
    Nothing -> do 
      let i' = i + (1::Int)
      put (i', Map.insert x' i t)
      return i

当我在包含大约400.000字的英文文本的文件上运行时,带有严格字节串键的版本使用大约50MB内存,带有Word8向量的版本使用6MB。

3 个答案:

答案 0 :(得分:5)

在没有其他答案的情况下,我会在这里走出困境。

  

当需要在Haskell中存储和比较大量小字符串时,最佳做法是什么?

如果小字符串是人类可读的(例如英文单词),则使用Text。如果它们只能由计算机读取,请使用ByteString。决定使用这些的严格或惰性变体取决于你如何构建和使用这些小字符串。

您不应该使用自己的Vector Word8个未加框的String。如果您遇到常规Text快于ByteStringVector的特定情况,请在StackOverflow上详细说明,我们会尝试找出原因。如果您执行详细分析,并且可以证明未Word8 Text的{​​{1}}始终比ByteString或{{1}}效果更好,那么请在邮件列表上启动对话,irc,reddit,等等;标准库不是一成不变的,总是欢迎改进。

但我认为你很可能只是在做一些奇怪的事情,正如hammar和shang所说的那样。

P.S。对于您的特定用例,您应该考虑根据您的需求提供更合适的数据结构,而不是存储大量小字符串。正如danr所暗示的那样。

答案 1 :(得分:3)

A(严格)ByteSting是未装箱的ForiegnPtrWord8以及两个未装箱的Ints的构造函数。

ForeignPtrAddr#(GHC prim)和ForeignPtrContents上的另一个构造函数:

data ForeignPtrContents
  = PlainForeignPtr !(IORef (Finalizers, [IO ()]))
  | MallocPtr      (MutableByteArray# RealWorld) !(IORef (Finalizers, [IO ()]))
  | PlainPtr       (MutableByteArray# RealWorld)

...

对于短字符串,ByteStrings只需要包含太多管理,以使其实际“字符串”数据的连续表示受益。

对于原始问题 - 我会检查你的语料库的平均单词长度,但是我看不到ByteString比String又名[Char]更有效,它使用每个Char 12个字节(来源原始的ByteString论文)。

对Haskellers的一般请求(不是针对原始问题的海报) - 请停止抨击String又名[Char] - 同时拥有String和Text(以及当你真正需要字节时的ByteString)是有意义的。或者使用Clean,其中连续的String表示更适合短字符串。

警告 - 我可能一直在查看ByteString内部的旧版本,了解它在内部使用的数据类型。

答案 2 :(得分:2)

我知道这是一篇有6年历史的帖子,但我最近也想知道这个帖子,发现这篇有用的博文:https://markkarpov.com/post/short-bs-and-text.html。似乎是的,这是一个公认的问题,Short(Text / ByteString)是解决方案。