Wie können Verzeichnisse schneller aufgelistet werden?
Ich habe einige Situationen, in denen ich Dateien rekursiv auflisten muss, aber meine Implementierungen waren langsam. Ich habe eine Verzeichnisstruktur mit 92784 Dateien.find
listet die Dateien in weniger als 0,5 Sekunden auf, aber meine Haskell-Implementierung ist viel langsamer.
Meine erste Implementierung dauerte etwas mehr als 9 Sekunden, die nächste Version etwas mehr als 5 Sekunden und ich bin derzeit auf etwas weniger als zwei Sekunden reduziert.
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
Der Test benötigt ungefähr 100 Megabyte Speicher (+ RTS -s) und das Programm gibt ungefähr 40% für GC aus.
Ich habe darüber nachgedacht, die Auflistung in einer WriterT-Monade mit Sequence als Monoid vorzunehmen, um die Erstellung von Concats und Listen zu verhindern. Ist es wahrscheinlich, dass dies hilft? Was soll ich sonst machen
Bearbeiten Ich habe die Funktion so bearbeitet, dass sie readDirStream verwendet, und sie hilft dabei, den Speicher niedrig zu halten. Es ist noch eine gewisse Zuweisung im Gange, aber die Produktivitätsrate liegt jetzt bei> 95% und dauert weniger als eine Sekunde.
Dies ist die aktuelle Version:
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