【发布时间】:2012-02-22 16:14:25
【问题描述】:
通常推荐的 Haskell 字符串类型似乎是 ByteString 或 Text。我经常使用大量的短(英文单词大小)字符串,并且通常需要将它们存储在 Data.Map 等查找表中。在许多情况下,我发现在这种情况下,字符串表占用的内存比字节字符串表要少。 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。
【问题讨论】:
-
您能否举一些代码示例,其中 ByteStrings 比 Strings 占用更多内存或比 Word8 向量“多得多”的内存?我不明白为什么会这样,除非你在做一些奇怪的事情。
-
@shang:如果您错误地将充满严格 ByteStrings 的映射的大小与包含字符串 thunk 的映射进行比较,我可以想象会发生这种情况。虽然更多细节会有所帮助。演示该问题的简短测试程序会特别好。
-
@hammar:是的,这是一种选择。另一个可能是您正在从一个大的 ByteString 中分割单词并保留对它的引用。
-
你可能想看看Data.Trie。