Paralelisieren von shutil.rmtree

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.
Antworten
Benutzeravatar
Amberfox
User
Beiträge: 10
Registriert: Montag 8. Oktober 2007, 15:29
Wohnort: Paderborn

Dienstag 6. November 2007, 09:49

Hallo Forum,

ich habe ein Python-Script erstellt welches eine große Anzahl an Ordnern mit vielen Dateien als Inhalt löscht.

Zuerst habe ich dies mit shutil.rmtree(folder) probiert, bin dann aber daran hängen geblieben, dass dies doch sehr lange dauert, da ein Ordner nach dem nächsten gelöscht wird.

Ich bin dann hergegangen und habe das Script so beschleunigt:

mydelcmd = "rm -r " + mydelfol
subprocess.Popen(mydelcmd, shell=True)

Nun werden alle Folder parallel (mehr oder weniger) gelöscht. Ich persönlich finde aber die erste Methode mit shutil schöner. Kann man dies auch parallelisieren?? Ein Tip in die richtige Richtung reicht mir schon :D

Grüße und Danke

Jochen
Everything was all good just a week ago...
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Dienstag 6. November 2007, 18:31

Ich weiss ja nicht was für eine Implementierung von rm du verwendest, aber die vom GNU Projekt arbeitet nicht parallel.
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
Benutzeravatar
Amberfox
User
Beiträge: 10
Registriert: Montag 8. Oktober 2007, 15:29
Wohnort: Paderborn

Dienstag 6. November 2007, 23:43

Hallo,

ist vielleicht ein bischen doof ausgedrückt von mir.

Natürlich arbeitet der rm nicht parallel, aber dadurch dass ich das für jeden Ordner absetze und nicht warten muss, bis der Thread zurückkommt, ist das "quasi parallel".

Wenn ich das mit shutil.rmtree mache, wartet mein Script bei jedem Ordner bis der rm-Thread aus dem Kern zurück kommt.

Ich suche nun eine Möglichkeit das zu optimieren :D

Grüße

Jochen
Everything was all good just a week ago...
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Dienstag 6. November 2007, 23:47

Hoi,

verstehe nicht ganz wozu das gut sein soll und so sind dies wirklich nur eine neugierige Fragen und keine besserwisserischen Bemerkungen:
Ist dieses quasiparallele Löschen wirklich schneller? Bei einer Platte gibt es nur einen Lese-/Schreibkopf, nicht wahr? Und bei einem Festplatten-Verbund, sollte das im Zusammenspiel mit Controller und OS doch auch keinen Unterschied machen, oder? Wenn doch, wo kommt der Unterschied her?

Gruß,
Christian
Benutzeravatar
Amberfox
User
Beiträge: 10
Registriert: Montag 8. Oktober 2007, 15:29
Wohnort: Paderborn

Mittwoch 7. November 2007, 07:37

Hi,

naja irgendwo hast du Recht. Bei mir ist es gefühlt schon etwas schneller. Da die rm-Threads asynchron in den Kern abgesetzt werden, kann ich die Zeit aber auch nicht mit einem time messen. Ich schau halt ins FS, wie lange es dauert bis alle Ordner weg sind.

Das Script läuft halt schneller durch, da das löschen der Ordner dann im Hintergrund läuft.

Ich lass es erstmal so wie es ist....aber noch eine Frage zum Verständnis,

shutil.rmtree macht doch auch nichts anderes, als das Shell "rm -r" aufzurufen, oder??

Grüße und Danke

Jochen
Everything was all good just a week ago...
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mittwoch 7. November 2007, 08:48

Amberfox hat geschrieben:shutil.rmtree macht doch auch nichts anderes, als das Shell "rm -r" aufzurufen, oder?
Hallo Jochen!

Nein, das macht es nicht. shutil.rmtree läuft jede Datei und jeden Unterordner rekursiv durch. Prüft jede Datei ob diese ein Ordner ist und übergibt je nach Art der Datei an ``os.remove`` oder ``os.rmdir``. Eine ziemliche Schleifenarbeit. So etwas ist direkt in C garantiert schneller.

Also der Aufwand von "rm" aus "coreutils" ftp://ftp.gnu.org/gnu/coreutils/ ist schon recht enorm. Du musst dir mindestens "rm.c" und "remove.c" ansehen umd einen Eindruck zu bekommen. Dass "rm" wirklich viel schneller ist, wundert mich nicht. In so einem Fall ist die perfekte Optimierung: per subprocess "rm" aufrufen.

Die Lösung, per subprocess auf so ein spezialisiertes Programm zurück zu greifen ist oft keine schlechte Lösung. Ich verstehe nicht, was dir daran nicht gefällt.

Allerdings würde ich die Argumente als Liste an subprocess übergeben. Dann kümmert sich subprocess um das korrekte Quoting.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Mittwoch 7. November 2007, 10:04

Hoi,

hab gerade die Quellen durchblättert:
gerold hat geschrieben: Eine ziemliche Schleifenarbeit. So etwas ist direkt in C garantiert schneller.
Ich weiß nicht,ob das einen sichtbaren Unterschied macht. Letztlich wird (bei Linux, aber davon gehe ich bei diesem Post mal aus) auf posix zurückgegriffen und alles weitere ist in C. Vermutung: Es braucht schon sehr viele Ordner (nicht sonstige Dateien), damit man hier einen Unterschied merkt - oder sieht das jemand anders?

Gruß,
Christian
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 7. November 2007, 11:40

gerold hat geschrieben:Die Lösung, per subprocess auf so ein spezialisiertes Programm zurück zu greifen ist oft keine schlechte Lösung. Ich verstehe nicht, was dir daran nicht gefällt.
Windows hat kein `rm`. Damit bringst du also platformabhängigkeit rein, wo es eigentlich keine bräuchte. Dann musst du testen ob es Windows ist und dort dann `del` aufrufen und somit für jede Platform gucken wie das Löschkommando dort ist.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mittwoch 7. November 2007, 11:56

Leonidas hat geschrieben:Windows hat kein `rm`. Damit bringst du also platformabhängigkeit rein, wo es eigentlich keine bräuchte. Dann musst du testen ob es Windows ist und dort dann `del` aufrufen und somit für jede Platform gucken wie das Löschkommando dort ist.
Hallo Leonidas!

Ist das ein Problem?

Code: Alles auswählen

>>> import sys
>>> if sys.platform.startswith("win"):
...     print "Windows"
... else:
...     print "Linux und Co"
...     
Windows
>>> 
(man könnte je nach Bedarf und Einsatzzweck noch weitere Plattformen in die Auswahl mit einbeziehen)

So etwas würde man natürlich nicht oder nur gut getestet für ein Python-Erweiterungsmodul verwenden. Aber sicher doch um schnell und einfach ein spezielles Problem zu lösen. Die ganze Linux-/Unix-Shellprogrammierung baut darauf auf, kleine Dienstprogramme gezielt einzusetzen. Und das funktioniert immer noch sehr gut.

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mittwoch 7. November 2007, 12:12

gerold hat geschrieben:Ist das ein Problem?

Code: Alles auswählen

>>> import sys
>>> if sys.platform.startswith("win"):
...     print "Windows"
... else:
...     print "Linux und Co"
...     
Windows
>>> 
(man könnte je nach Bedarf und Einsatzzweck noch weitere Plattformen in die Auswahl mit einbeziehen)
Klar, das geht schon. Aber weißt du wie der Befehl fürs Löschen unter Plan 9, Inferno, und $IRGENDEIN_EXOTISCHES_OS_AUF_DEM_PYTHON_LÄUFT ist? Du kannst ja für die bekannten Platformen so etwas anbieten, aber generell würde ich das als "Unschön" bezeichnen. Du nutzt ja sicher auch Pythons Stdlib, obwohl man unter Windows einige Sachen auch über `ctypes` und die MSVCRT lösen kann.
Der Code ist optimalerweise für alle Plattformen gleich. Das `shutil.rmtree` nicht sonderlich schnell ist mag ja sein, aber da wäre es besser dem Interpreter eine Implementation zu geben, die besser ist. Davon profitieren alle. Klar, das klingt nun etwas arg "abgehoben" und die Lösung Subprozesse zu starten um Dinge zu erledigen geht ja auch, aber meines Ermessens ist sie einfach nicht schön.
gerold hat geschrieben:Aber sicher doch um schnell und einfach ein spezielles Problem zu lösen. Die ganze Linux-/Unix-Shellprogrammierung baut darauf auf, kleine Dienstprogramme gezielt einzusetzen. Und das funktioniert immer noch sehr gut.
Das dachten sich auch die Entwickler von Git. Das ist schnell und eine Mischung aus C, Perl und bash die unter Windows nicht richtig lauffähig ist. Daran ist nicht nur der C-Teil schuld.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Mittwoch 7. November 2007, 12:15

Das wäre ein Problem falls es sich wirklich nur um "gefühlte" Geschwindigkeit handelt. Also ich würde messen wieviel es bringt bevor ich mir eine eventuell unnötige Platformabhängigkeit einbaue.
Benutzeravatar
Amberfox
User
Beiträge: 10
Registriert: Montag 8. Oktober 2007, 15:29
Wohnort: Paderborn

Mittwoch 7. November 2007, 19:17

Hallo,

vielen Dank für die Denkanstöße!!
Also ich denke ich lasse es dann erstmal so. Die angesprochenen rm.c und remove.c schaue ich mit interesse halber einfach mal an.

Die Platformunabhängigkeit ist in meinem Fall erstmal nicht ganz so wichtig, daher nutze ich das Aufrufen des "rm", um einfach die gefühlte Geschwindigkeit zu haben. Ich schau mal ob ichs doch schaffe die Zeit zu stoppen und melde mich dann, wenn ich wirklich Testergebnisse habe, was schneller geht.

Viele Grüße in die Runde

Jochen
Everything was all good just a week ago...
Antworten