Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
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?
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?
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.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008] Bitbucket, Github
@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.
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)?
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008] Bitbucket, Github
@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.
@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.
@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.
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.
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
(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.
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.
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.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008] Bitbucket, Github
@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.