我有几种情况需要递归列出文件,但我的实现速度很慢。我的目录结构中有92784个文件。find
在不到0.5秒的时间内列出了文件,但我的Haskell实现要慢很多。
我的第一个实现需要超过9秒才能完成,下一个版本需要超过5秒,而我目前的实现则少于2秒。
listFilesR :: FilePath -> IO [FilePath]
listFilesR path = let
isDODD "." = False
isDODD ".." = False
isDODD _ = True
in do
allfiles <- getDirectoryContents path
dirs <- forM allfiles $ \d ->
if isDODD d then
do let p = path </> d
isDir <- doesDirectoryExist p
if isDir then listFilesR p else return [d]
else return []
return $ concat dirs
这个测试需要大约100兆字节的内存(+RTS -s),程序在GC中花费了约40%的时间。
我考虑使用WriterT单子和Sequence作为单子来进行列表处理,以避免拼接和列表创建。这样做有可能有帮助吗?还有什么其他建议吗?
编辑:我已经修改了函数,使用readDirStream,它有助于保持内存占用率低。仍然会发生一些分配,但生产率现在是>95%,运行时间少于一秒。
这是当前版本:
list path = do
de <- openDirStream path
readDirStream de >>= go de
closeDirStream de
where
go d [] = return ()
go d "." = readDirStream d >>= go d
go d ".." = readDirStream d >>= go d
go d x = let newpath = path </> x
in do
e <- doesDirectoryExist newpath
if e
then
list newpath >> readDirStream d >>= go d
else putStrLn newpath >> readDirStream d >>= go d