Seite 1 von 1
getfoldersize zu langsam?
Verfasst: Dienstag 29. März 2011, 11:38
von darktrym
Hallo,
ich habe mir ein Skript gebastelt, welches die Verzeichnisgröße ermittelt, leider dauert das bissl arg lang.
Gibt's schnellere pythonische Methoden um das Problem zu lösen?
Code: Alles auswählen
#! /usr/bin/env python
import os
#import cProfile
def getFolderSize(start_dir):
size = 0
for curr_dir, dirs, files in os.walk(start_dir):
curr_size = 0
os.chdir(curr_dir)
for filename in files:
curr_size += os.path.getsize(filename)
size += curr_size
#print "%s = %i" % (curr_dir, curr_size)
return size
#cProfile.run('getFolderSize(os.getcwd())')
print "directory size: %i" % getFolderSize(os.getcwd())
Re: getfoldersize zu langsam?
Verfasst: Dienstag 29. März 2011, 11:48
von Hyperion
Ich kapiere nicht, inwiefern os.chdir() da notwendig ist. Wozu die beiden Bezeichner size und curr_size? Einer sollte doch reichen.
Naja, Du musst ja jede Datei einmal anfassen, um die Größe zu ermitteln. Wenn Du halt zig tausend davon hast, dann kann das schon ein wenig dauern. Ich nehme mal an, dass Du in der Standard-Lib geguckt hast, ob es da nichts fertiges gibt?
Re: getfoldersize zu langsam?
Verfasst: Dienstag 29. März 2011, 12:08
von darktrym
Die Variablen werden später noch gebraucht.
Die Suchmaschine hat mir keine Hinweise geliefert, ob sowas bereits integriert ist. Was mich ein biss. wundert ist, dass os.path.getsize auch mit Verzeichnissen funktioniert nur kann ich mit der Ausgabe nichts anfangen.
Re: getfoldersize zu langsam?
Verfasst: Dienstag 29. März 2011, 12:17
von BlackJack
@darktrym: Nur dass das nicht untergeht: das `os.chdir()` sollte da weg! Das Arbeitsverzeichnis ist etwas was für den ganzen Prozess gilt. Wenn man daran herum spielt, schreibt man Code der nur schlecht mit anderem zusammen arbeitet. Früher oder hat man an anderer Stelle im Programm Code, der so überhaupt nicht damit rechnet dass das Arbeitsverzeichnis verändert wurde.
Die Grösse von Verzeichnissen ist die Grösse des Verzeichnisses selber. Die Dateinamen und Attribute die in einem Verzeichnis stecken, benötigen selbst ja auch Speicherplatz.
Re: getfoldersize zu langsam?
Verfasst: Dienstag 29. März 2011, 12:44
von darktrym
Das mit os.chdir sehe ich ein, war nur eine Optimierung meinerseits um nicht den absoluten Pfad der Datei angeben zu müssen.
Die Sache mit dem Verzeichnis verstehe ich aber nicht. Wenn ich die Anweisung so formuliere erwarte ich ja nicht irgendwelche esoterischen Werte. Angenommen im Verzeichnis liegt eine Datei(447Byte), belegt werden auf dem Datenträger ein Block a 4KB, wieso wird dann 64KB! von der Funktion zurückgegeben(unter Windows 7)?
Re: getfoldersize zu langsam?
Verfasst: Dienstag 29. März 2011, 13:04
von BlackJack
@darktrym: Weil das Verzeichnis dort anscheinend 64 KiB gross ist. Die Grösse der Datei und wie viel die auf der Platte belegt ist dabei übrigens egal. Es geht da nur um die Metadaten, also Dateinamen, Rechte, Zeitstempel, ACLs, und so weiter, die in dem Verzeichnis gespeichert sind. Ausserdem solltest Du nicht damit rechnen, dass die Grösse sich bei jeder enthaltenen Datei ändert -- wenn Du da zwei statt einer Datei im Verzeichnis hast, dann werden da wahrscheinlich keine 128 KiB draus, weil sicher mehr als ein Dateieintrag in die 64 KiB passt.
Re: getfoldersize zu langsam?
Verfasst: Dienstag 29. März 2011, 22:50
von darktrym
Ok, das Problem ist wohl os.walk. Diese Variante läuft ohne os.walk und braucht dafür nur die halbe Zeit!
Code: Alles auswählen
import os
#import cProfile
def getFolderSize(directory):
size = 0
dirs = [directory]
while dirs:
curr_size = 0
directory = dirs.pop()
os.chdir(directory)
for item in os.listdir(directory):
if os.path.isdir(item):
dirs.append(os.path.join(directory, item))
else:
curr_size += os.path.getsize(item)
size += curr_size
#print "%s = %i" % (directory, curr_size)
return size
#cProfile.run('getFolderSize(os.getcwd())')
print "directory size: %i" % getFolderSize(os.getcwd())
Re: getfoldersize zu langsam?
Verfasst: Dienstag 29. März 2011, 23:16
von BlackJack
@darktrym: Da ist immer noch das `os.chdir()` drin…
Wie ist die Messung eigentlich zustande gekommen? Ich will die nicht anzweifeln -- nur sicherstellen das die Ausgangsbedingungen auch wirklich vergleichbar waren. Der Cache wurde vor beiden Testläufen geleert? Also nicht das der zweite Testlauf die ganzen Daten schon im RAM hatte.
Re: getfoldersize zu langsam?
Verfasst: Mittwoch 30. März 2011, 00:07
von lunar
@BlackJack: Die gezeigte Variante ist im Gegensatz zu "os.walk()" nicht rekursiv, was angesichts der Kosten für einen Funktionsaufruf bei großen Hierarchien schon spürbare Unterschiede mit sich bringen kann, auch wenn ich eine Halbierung der Ausführungszeit nicht wirklich glaube.
Re: getfoldersize zu langsam?
Verfasst: Mittwoch 30. März 2011, 10:49
von deets
@lunar
Mit Verlaub, aber im Kontext von Festplattenoperationen geht ein Funktionsaufruf mehr schlicht im Rauschen unter.
Wenn der OP solche massiven Effekte beobachtet hat, dann ist das IMHO auf dein Plattencache zurueckzufuehren, da hat BlackJack schon den richtgen Riecher, die Methodik zu hinterfragen.
Re: getfoldersize zu langsam?
Verfasst: Mittwoch 30. März 2011, 10:55
von b.esser-wisser
Ich hab das mal
minimal optimiert, aber wenn ich beide Funktionen auf den selben Pfad loslasse - egal in welcher Reihenfolge - ist die zweite 10x schneller (logisch, jedes OS hat 'nen Cache für die Festplatte).
Wie misst man das denn 'richtig' (Cache, os.path.join vs. os.chdir, rekursion )? :K
edit.:
ps.: bei dem script im pastebin: Linux-nutzer sollten wahrscheinlich besser time.time() statt time.clock() benutzen
Re: getfoldersize zu langsam?
Verfasst: Mittwoch 30. März 2011, 11:20
von deets
Kann ich nicht nachvollziehen:
Code: Alles auswählen
(master)dir@client8131:~/projects/ableton/master$ time python /tmp/a.py
directory size: 723902605
real 0m2.360s
user 0m0.188s
sys 0m0.160s
(master)dir@client8131:~/projects/ableton/master$ time python /tmp/a.py
directory size: 723902605
real 0m0.217s
user 0m0.120s
sys 0m0.096s
(master)dir@client8131:~/projects/ableton/master$ time python /tmp/a.py
directory size: 723902605
real 0m0.217s
user 0m0.120s
sys 0m0.096s
(master)dir@client8131:~/projects/ableton/master$ time python /tmp/b.py
directory size: 723902605
real 0m0.333s
user 0m0.184s
sys 0m0.144s
(master)dir@client8131:~/projects/ableton/master$ time python /tmp/b.py
directory size: 723902605
real 0m0.332s
user 0m0.232s
sys 0m0.096s
(master)dir@client8131:~/projects/ableton/master$
Variante a ist dabei etwas ungluecklich benannt deine zweite, und b die von os.walk. Es gibt zwar minimale Vorteile bezueglich a, aber nicht Faktor 10. Der erste Lauf zeigt ganz gut, wie der Plattencache anspringt.
Ich habe mir mal die Implementation von os.walk angeschaut. Die ist ein kleeeeines bisschen komplexer als deine home-brew-geschichte, und unter anderem ruft sie islink auf, was ein zusaetzlicher syscall ist. Das koennte die zeitlichen Nachteile erklaeren.
Re: getfoldersize zu langsam?
Verfasst: Mittwoch 30. März 2011, 11:30
von BlackJack
Neben dem mehrfachen laufen lassen um den Cache zu füllen bevor man das Programm testet, könnte man auch vor jedem Lauf die Caches leeren. Unter Linux zum Beispiel mit ``echo 3 > /proc/sys/vm/drop_caches`` mit "root"-Rechten.
Dann misst man zwar nicht nur das Programm, bekommt aber vielleicht praxisnähere Zahlen. Und wahrscheinlich einen deutlich kleineren Unterschied zwischen den Varianten.
Re: getfoldersize zu langsam?
Verfasst: Mittwoch 30. März 2011, 19:36
von darktrym
os.chdir() kommt noch raus, "du hast mein Ehrenwort"; es diente alleinig zum Vergleich beider Varianten.
Hat mich ehrlich gesagt etwas verwundert, dass die spezialisierte Variante langsamer ist als die allgemeine, selbstgebastelte.
Mein Test bezog sich auf ein Verzeichnis mit 2643 Unterverzeichnissen 37331 Dateien, knapp 1.14 GB, mehrere Repos.
Re: getfoldersize zu langsam?
Verfasst: Mittwoch 30. März 2011, 20:16
von BlackJack
@darktrym: Ich glaube jetzt hast Du gerade "allgemein" und "spezialisiert" verwechselt. Deine ist die Spezialisiertere. `os.walk()` ist allgemeiner -- damit kann man nicht nur Dateigrössen zusammenrechnen. Man kann dort auch während des Iterierens Verzeichnisse filtern, in die dann nicht weiter rein gegangen wird. Und man kann die Ergebnisse "bottom up" liefern lassen, also die Blätter des Verzeichnisbaums zuerst.