如何更快地列出目录?

Mas*_*sse 9 io optimization file-io haskell

我有一些情况需要递归列出文件,但我的实现速度很慢.我有一个包含92784个文件的目录结构.find在不到0.5秒的时间内列出文件,但我的Haskell实现速度要慢得多.

我的第一个实现需要花费9秒多的时间来完成,下一个版本需要5秒多一点时间,我现在已经下降到不到两秒钟了.

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
Run Code Online (Sandbox Code Playgroud)

该测试需要大约100兆字节的内存(+ RTS -s),并且该程序在GC中花费大约40%.

我正在考虑在WriterT monad中进行列表,将Sequence作为monoid来阻止concats和list创建.这有帮助吗?我还该怎么办?

编辑:我已经编辑了使用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 
Run Code Online (Sandbox Code Playgroud)

Tsu*_*Ito 5

我认为System.Directory.getDirectoryContents构建一个完整的列表,因此使用了很多内存.怎么用System.Posix.DirectorySystem.Posix.Directory.readDirStream逐个返回一个条目.

此外,FileManip库可能很有用,虽然我从未使用它.