¿Cómo enumerar directorios más rápido?
Tengo algunas situaciones en las que necesito enumerar archivos de forma recursiva, pero mis implementaciones han sido lentas. Tengo una estructura de directorio con 92784 archivos.find
enumera los archivos en menos de 0,5 segundos, pero mi implementación de Haskell es mucho más lenta.
Mi primera implementación tardó un poco más de 9 segundos en completarse, la próxima versión un poco más de 5 segundos y actualmente tengo menos de dos segundos.
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
La prueba toma alrededor de 100 megabytes de memoria (+ RTS -s), y el programa gasta alrededor del 40% en GC.
Estaba pensando en hacer el listado en una mónada WriterT con Sequence como el monoide para evitar los concatos y la creación de listas. ¿Es probable que esto ayude? ¿Que más deberia hacer?
Editar: He editado la función para usar readDirStream, y ayuda a mantener baja la memoria. Todavía está sucediendo alguna asignación, pero la tasa de productividad es> 95% ahora y se ejecuta en menos de un segundo.
Esta es la versión actual:
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