【发布时间】:2012-04-05 21:08:15
【问题描述】:
我用 Haskell 编写了一个程序,它必须加载和解析 UTF8 格式的大文本文件。该文件代表一个字典,每行都有键:值对。在我的程序中,我想要一个用于快速字典搜索的 Data.Map 容器。我的文件大约 40MB,但在将其加载到我的程序后,使用了 1.5 GB 的 RAM,并且从未释放。我做错什么了?内存使用量是预期的吗?
这是我的程序中的代码示例:
模块主要在哪里
import Engine
import Codec.Archive.Zip
import Data.IORef
import System.IO
import System.Directory
import qualified System.IO.UTF8 as UTF8
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.UTF8 as BsUtf
import qualified Data.Map as Map
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade
maybeRead :: Read a => BsUtf.ByteString -> Maybe a
maybeRead s = case reads $ BsUtf.toString s of
[(x, "")] -> Just x
_ -> Nothing
parseToEntries :: [BsUtf.ByteString] -> [(BsUtf.ByteString, Int)]
parseToEntries [] = []
parseToEntries (x:xs) = let (key, svalue) = BsUtf.break (==':') x
value = maybeRead svalue
in case value of
Just x -> [(key, x)] ++ parseToEntries xs
Nothing -> parseToEntries xs
createDict :: BsUtf.ByteString -> IO (Map.Map BsUtf.ByteString Int)
createDict str = do
let entries = parseToEntries $ BsUtf.lines str
dict = Map.fromList entries
return (dict)
main :: IO ()
main = do
currFileName <- newIORef ""
dictZipFile <- B.readFile "data.db"
extractFilesFromArchive [] $ toArchive dictZipFile
dictFile <- UTF8.readFile "dict.txt"
dict <- createDict $ BsUtf.fromString dictFile
...
searchAccent :: Map.Map BsUtf.ByteString Int -> String -> Int
searchAccent dict word = let sword = BsUtf.fromString $ map toLower word
entry = Map.lookup sword dict
in case entry of
Nothing -> -1
Just match -> 0
【问题讨论】:
-
我对 Haskell 有点生疏,但是 iirc,
++语法是内存昂贵的,而 cons 运算符 (:) 很便宜。是否可以使用(key, x) : parseToEntries xs之类的东西?再次 。 . .我的 Haskell 很生锈,所以这可能是一种方法。 -
@jpm,它的内存开销取决于
++的第一个参数的长度。在这种情况下,它是不相关的。 -
@maxtaldykin 啊,这很有道理。感谢您的澄清。
-
@jpm,在冈崎书page 9中有关于
++如何工作的漂亮图片 -
haskell.org/pipermail/haskell-cafe/2010-August/081772.html 讨论了您正在使用的库的用途,这与您的不同。解压缩一个 23 兆字节的 zip 存档大约需要 4 分钟,没有做任何其他事情,但通过其他方式不到 10 秒。我不认为 (++) 和字符串与字节串是主要的麻烦。