【发布时间】:2012-09-12 17:02:28
【问题描述】:
我正在 Haskell 中编写一些简单的字符计数例程,将统计信息存储在新的数据类型中:
data Stat = Stat {
stChars :: !Int,
stVowels :: !Int,
stPairEL :: !Int,
stWords :: !Int
}
我在成百上千个纯文本文件上运行此程序,每个文件大约 50K--100K。
tabulateFile :: FilePath -> IO Stat
tabulateFile path = do
putStrLn path
contents <- L.readFile path
return $! tabulateText ' ' contents defaultStat
我没有使用左折叠,而是使用原始递归,这样我就可以保留前一个字符。
tabulateText :: Char -> L.ByteString -> Stat -> Stat
tabulateText lastChr bs stat =
case U.uncons bs of
Nothing -> stat
Just (chr, newBs) ->
tabulateText lchr newBs (countChar lastChr lchr stat)
where lchr = toLower chr
{-# INLINE countChar #-}
countChar :: Char -> Char -> Stat -> Stat
countChar !lastChr !chr !(Stat stChars stVowels stPairEL stWords) =
Stat
(stChars + 1)
(stVowels + (countIf $ isVowel chr))
(stPairEL + (countIf (lastChr == 'e' && chr == 'l')))
(stWords + (countIf ((not $ isLetter lastChr) && isLetter chr)))
isVowel :: Char -> Bool
isVowel c = Set.member c vowels
vowels = Set.fromAscList ['a', 'e', 'i', 'o', 'u', ...] -- rest of vowels elided
现在,它比运行cat * | wc 慢两倍多,但我的直觉告诉我,文件 I/O 应该远远超过所需的 CPU 时间。简单地使用 cat * | wc 处理大约 20MB/s 的热缓存,但使用我的 Haskell 程序(使用 -O 编译)运行速度低于 10MB/s,即使经过一些基本优化。 Profiling告诉我大部分时间都花在tabulateText和countChar上。
我有什么遗漏的地方可以在这里优化吗?
编辑:完整的文件粘贴到http://hpaste.org/74638
【问题讨论】:
-
您能否将完整的文件发布到一些 hpaste 并在此处发布链接。它包含许多缺失的功能,我不想实现这些功能以便能够运行您的代码。
-
是的,对不起,我没有早点把它弄出来。我已将链接添加到问题的末尾。
标签: optimization haskell nlp