Como listar diretórios mais rapidamente?
Tenho algumas situações em que preciso listar arquivos recursivamente, mas minhas implementações têm sido lentas. Eu tenho uma estrutura de diretórios com arquivos 92784.find
lista os arquivos em menos de 0,5 segundos, mas minha implementação do Haskell é muito mais lenta.
Minha primeira implementação demorou um pouco mais de 9 segundos para ser concluída, a próxima versão um pouco mais de 5 segundos e atualmente estou com menos de dois 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
O teste ocupa cerca de 100 megabytes de memória (+ RTS-s) e o programa gasta cerca de 40% no GC.
Eu estava pensando em fazer a listagem em uma mônada do WriterT com Sequence como o monóide, para impedir as concats e a criação da lista. É provável que isso ajude? O que mais devo fazer?
Editar: Editei a função para usar o readDirStream, e isso ajuda a manter a memória baixa. Ainda está acontecendo alguma alocação, mas a taxa de produtividade é> 95% agora e é executada em menos de um segundo.
Esta é a versão atual:
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