У меня есть несколько ситуаций, когда мне нужно перечислить файлы рекурсивно, но мои реализации были медленными. У меня есть структура каталогов с 92784 файлами. find
выводит список файлов менее чем за 0,5 секунды, но моя реализация Haskell намного медленнее.
Моя первая реализация заняла чуть более 9 секунд, следующая версия - чуть более 5 секунд, и я ' m в настоящее время составляет чуть менее двух секунд.
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), и программа тратит около 40% на сборщик мусора.
Я думал сделать листинг в монаде WriterT с Sequence в качестве моноида, чтобы предотвратить конкатенацию и создание списка. Это может помочь? Что еще мне делать?
Edit: Я отредактировал функцию, чтобы использовать 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