erj*_*ang 2 optimization haskell nlp
我正在Haskell中编写一些简单的字符计数例程,将统计信息存储在一个新的数据类型中:
data Stat = Stat {
stChars :: !Int,
stVowels :: !Int,
stPairEL :: !Int,
stWords :: !Int
}
Run Code Online (Sandbox Code Playgroud)
我正在运行数百或数千个纯文本文件,每个文件大约50K - 100K.
tabulateFile :: FilePath -> IO Stat
tabulateFile path = do
putStrLn path
contents <- L.readFile path
return $! tabulateText ' ' contents defaultStat
Run Code Online (Sandbox Code Playgroud)
我没有使用fold-left,而是使用原始递归,因此我可以保留前一个字符.
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
Run Code Online (Sandbox Code Playgroud)
现在,它的运行速度是运行速度的两倍多cat * | wc,但我的直觉告诉我,文件I/O应该超过良好余量所需的CPU时间.使用cat * | wc热缓存大约使用大约20MB/s的进程,但使用我的Haskell程序(编译-O)以低于10MB/s的速度运行,即使经过一些基本的优化.剖析告诉我,大部分时间花在tabulateText和countChar.
有什么我想念的东西,我可以在这里进行优化吗?
编辑:完成文件粘贴到http://hpaste.org/74638
Don*_*art 10
您应该提供导入,以便有人可以编译代码.但是,这里有几件看起来很可能:
-O2 -funbox-strict-fields(获得严格字段的好处)lastChr,和stat例如
isSpaceChar8 :: Char -> Bool
isSpaceChar8 c =
c == ' ' ||
c == '\t' ||
c == '\n' ||
c == '\r' ||
c == '\f' ||
c == '\v' ||
c == '\xa0'
Run Code Online (Sandbox Code Playgroud)
这将内联和优化很好.
不知道是什么countIf,但它糟透了.我怀疑它是一个if你返回0?怎么样:
Stat
(a + 1)
(if isVowel c then a + 1 else a)
...
Run Code Online (Sandbox Code Playgroud)
然后看看核心.
| 归档时间: |
|
| 查看次数: |
246 次 |
| 最近记录: |