Warum ist popen.communicate() dramatisch langsamer als subprocess.check_output()

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
Grendel
User
Beiträge: 50
Registriert: Samstag 19. Dezember 2015, 16:06

Hallo zusammen,
ich benötige den Output eines externen Prozesses, den ich mit subprocess.check_output() gestartet habe. Soweit so gut, funktioniert und ist recht schnell. Nun muss ich aber das Ende des externen Prozesses abwarten, sonst versucht mein Programm im weiteren Verlauf auf Daten zuzugreifen, die noch nicht vollständig vorhanden sind. subprocess.check_output() kann dies nicht, also versuchte ich popen.communicate(). Ich habe es entsprechend der Python Dokumentation implementiert, nur leider läuft der externe Prozess nun extrem langsam. Ist das normal? Sollte es eigentlich nicht sein, da nach meinem Wissen subprocess.check_output() lediglich eine Art vorkonfiguriertes popen ist. Mit anderen Worten: subprocess.check_output() arbeitet hinter den Kulissen ebenfalls mit popen.communicate.
BlackJack

@Grendel: `check_output()` ist in Python geschrieben, Du kannst also nachsehen was das macht. Und es verwendet in der Tat die `communicate()`-Methode. Was es in der Tat nicht macht,ist das Ende des externen Prozesses abzuwarten. Und genau das wird dann wohl der Zeitunterschied sein, den Du siehst, wenn Du auf das Ende wartest.
Grendel
User
Beiträge: 50
Registriert: Samstag 19. Dezember 2015, 16:06

Rufe ich das externe Programm mit den gleichen Parametern direkt aus einem Terminal auf, so ist es etwa um den Faktor 25(!) schneller. Die Zeitdifferenz kann also nicht nur aus der Wartezeit bis zum Beenden des Prozesses resultieren. Das Kommandozeilenprogramm an sich verarbeitet zwei Index-Dateien zu einer (es handelt sich hierbei nicht um ein reines aneinander hängen) und das wird, wenn ich es mit popen.communicate() aufrufe, schneckenlangsam. Öffnet man einen Datei-Explorer und schaut sich an, was in dem entsprechenden Verzeichnis passiert, so kann man dem Programm direkt bei der Arbeit zusehen. Auf der Kommandozeile ausgeführt, ist das nicht möglich, da es viel zu schnell arbeitet.
__deets__
User
Beiträge: 14523
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das einzige das mir dazu einfällt: kann es sein, das die Umleitung der Standardausgabe anders oder nicht erfolgt? Da könnte ich mir vorstellen, das ein Programm dadurch anderes Verhalten zeigt.

Probier doch mal stdout und stderr mittels subprocess.PIPE umzulenken, auch wenn's dich nicht interessiert was dabei rauskommt.
BlackJack

@Grendel: Also erst einmal kann `communicate()` gar nicht langsamer sein als `check_output()`, denn `communicate()` wird in `check_output()` ja benutzt *plus* ein wenig zusätzlicher Code. Du musst das also noch irgendeinen Unterschied haben. Den wir nicht kennen.
Grendel
User
Beiträge: 50
Registriert: Samstag 19. Dezember 2015, 16:06

Das Problem kommt aus einer eher unerwarteten Ecke. Und zwar kann man optional die Index-Dateien ZIP komprimieren (als eine Art Backup), und zwar bevor der externe Prozess gestartet wird, der auf diese Index-Dateien zugreift. Wenn man diese Option aber auswählt, wirft das externe Kommando eine Exception bzw. es erzeugt einen Exit-Code 1. Lässt man das Komprimieren sein, so läuft alles fehlerfrei. Möglicherweise liegt hier ein Timing-Problem vor, vielleicht ist die Komprimierung noch nicht beendet und das externe Kommando versucht, auf die noch in Bearbeitung befindlichen Dateien zuzugreifen. Dann würde sich die Frage stellen, wie ich den Komprimiervorgang abwarten kann, denn hierzu nutze ich die Python Lib "zipfile".
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@Grendel: ohne dass Du Code zeigst, ist das hier doch alles wildes Herumraten.
Antworten