【发布时间】:2015-09-10 19:30:36
【问题描述】:
在我的 Haskell 项目之一 RuzzSolver 中使用 TemplateHaskell 时,我遇到了内存消耗问题。 Sources of RuzzSolver are available on GitHub .
为了获得良好的性能,我将约 380000 个单词的字典加载到 Tree 结构中(来自容器包)。这极大地加快了网格的求解速度,但加载本身需要一些时间(取决于 CPU,在 1 到 2 秒之间)。
我想在编译时使用 TemplateHaskell 直接创建结构。
因此我转换了字典加载:
-- Dictionary.hs, line 155
getDictionary :: String -> IO Dictionary
getDictionary dictionaryFilePath = do
content <- readFile dictionaryFilePath
return $ foldl (+++) [] (createTree <$> lines content)
进入这个函数:
-- Dictionary.hs, line 164
getDictionaryQ :: String -> Q Exp
getDictionaryQ dictionaryFilePath = do
content <- runIO $ readFile dictionaryFilePath
lift $ foldl (+++) [] (createTree <$> lines content)
它允许我从:
-- ruzzSolver.hs, line 68
dictionary <- getDictionary "dictionary/ruzzdictionary.txt"
到:
-- ruzzSolver.hs, line 68
let dictionary = $(getDictionaryQ "dictionary/ruzzdictionary.txt")
它(应该)可以工作,但是编译需要太多内存!在我的 8 Gb PC 上,当 GHC 消耗到 12 GB 时,我不得不停止它。将字典减少到 38000 个单词可以编译,但仍需要 3 到 4 GB。
在编译这个 TemplateHaskell 代码时,有没有办法让 GHC 使用更少的内存?或者以其他方式将此结构嵌入到可执行文件中?
【问题讨论】:
-
这与您的问题没有直接关系,但听起来您将树用作某种特里树。有一些图书馆提供尝试,包括bytestring-trie 和word-trie。
-
@dfeuer 你是对的,这是一个尝试:-)
-
似乎加载几个 meg 文件应该没什么大不了的。仔细查看您的加载代码。您是否使用(懒惰的)bytestrings 来加载文件?我希望文件已经排序?你能想出一个文件表示,它将树存储在一个只需要很少计算加载的状态吗?例如使用Data.Binary?疯狂的想法:基于mmap实现一个trie。
-
显然,如果您正在预计算一个巨大的 AST,您应该关闭该模块的优化。
-
@luqui 是的,这是一个巨大的 AST ;-) 文件已经排序。我不使用(惰性)字节串,我使用标准的 readFile。我曾经尝试使用 Text 函数来加载文件,但没有任何区别。