os.popen3 - child_stderr.read() haengt unter bestimmten Umstaenden (Win XP)

Hallo Pythoneers, ich benutze Python 2.4 unter Win-XP und wundere mich gerade ueber folgendes: Wenn man: (child_stdin, child_stdout, child_stderr) = os.popen3(cmd) ausfuehrt, dann bleibt ein anschliessendes: err = child_stderr.read() immer dann haengen, wenn: - 'cmd' mehr als 4094 characters in child_stdout schreibt und - wenn man child_stderr.read() ausfuehrt bevor child_stdout.read() ausgefuehrt wurde. In anderen Worten: Nach os.popen3() immer erst child_stdout.read() und danach erst child_stderr.read() ausfuehren. Dieses Problem ist MS Windows spezifisch. Unter Linux funktioniert es. Vermutlich macht es Sinn das als Fussnote mit in die Python Doku aufzunehmen, sonst verzweifeln viele arme User deren os.popen3() Aufrufe manchmal haengen und manchmal nicht. Was meint Ihr dazu ? Juergen Hier mein Testcode: """ import os def test1Popen(nrOfChars): # reading child_stdout first cmd = 'python -c "print %s * %d",'%("'x'", nrOfChars) (child_stdin, child_stdout, child_stderr) = os.popen3(cmd) print "trying to read child_stdout" print "child_stdout = '%s'"%(child_stdout.read()) print "trying to read child_stderr - %d chars written stdout"%(nrOfChars) print "child_stderr = '%s'"%(child_stderr.read()) def test2Popen(nrOfChars): # reading child_stderr first cmd = 'python -c "print %s * %d",'%("'x'", nrOfChars) (child_stdin, child_stdout, child_stderr) = os.popen3(cmd) print "trying to read child_stderr - %d chars written stdout"%(nrOfChars) print "child_stderr = '%s'"%(child_stderr.read()) print "trying to read child_stdout" print "child_stdout = '%s'"%(child_stdout.read()) test1Popen(4094) # ok test2Popen(4094) # ok test1Popen(4095) # ok test2Popen(4095) # hangs forever """ _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de

Rauch, Juergen (Juergen) schrieb:
Was meint Ihr dazu ?
Ich finde das überhaupt nicht überraschend, sondern selbstverständlich. In Deinem Beispiel wird doch nichts auf stderr geschrieben, oder? Damit geht child_stderr.read() erst zuende, wenn child_stderr geschlossen wird (wenn also klar ist, dass da keine Daten mehr kommen). Die Frage ist nun, ob das print-Kommando im Kindprozess zuende geht oder nicht. print gibt auf stdout aus, aber das ist ja eine Pipe. Dh. das Betriebssystem puffert eine gewisse Menge Daten, aber nicht beliebig viele. Wenn die Pipe "voll" ist, werden weitere Schreibaktionen im Kindprozess blockiert, dh. der Kindprozess terminiert nicht. Der Kindprozess *würde* weiterarbeiten, wenn der Elternprozess aus der Pipe liest. Macht er aber (in test2Popen) nicht: er hängt ja im read auf stderr. Diese Situation nennt man "deadlock": beide Prozesse warten gegenseitig darauf, dass der andere eine bestimmte Aktion ausführt, die der aber nicht ausführen wird. Das Problem ist nicht Windows-spezifisch, nur die Puffergröße ist es. Probier's mal mit 100000 auf Linux; in Linux 2.6. ist die Puffergröße einer Pipe 64k. Es gibt drei traditionelle Lösungsstrategien für dieses Problem: 1) Multi-threading: stdout und stderr werden in separaten Threads gelesen 2) select/poll/WaitForMultipleObjects: anstatt blockierend zu lesen, testet man, von welchem Filedeskriptor gelesen werden kann 3) "Protokolle": zwischen Elternprozess und Kindprozess wird ein Regime festgelegt, bei dem der Pipe-Puffer nicht vollaufen kann (weil beide immer synchron lesen und schreiben). Diese Phänomene sind in jedem guten Buch über Betriebssysteme erläutert. Ciao, Martin _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de

Martin, danke fuer die ausfuehliche Antwort, du hast natuerlich Recht, jetzt sind auch mir die Zusammenhaenge klar geworden. Da kann man mal sehen - Python verleiht zwar Fluegel, aber deswegen kann man sich trotzdem nicht ueber solch profane Dinge wie Buffergroessen hinwegsetzen. Weiss jemand ob es angedacht ist eine der unten genannten Strategien zu integrieren und popen damit idiotensicher zu machen ? Juergen -----Original Message----- From: "Martin v. Löwis" [mailto:martin@v.loewis.de] Sent: 25 October 2006 13:05 To: Rauch, Juergen (Juergen) Cc: python-de@python.net Subject: Re: [Python-de] os.popen3 - child_stderr.read() haengt unter bestimmten Umstaenden (Win XP) Rauch, Juergen (Juergen) schrieb:
Was meint Ihr dazu ?
Ich finde das überhaupt nicht überraschend, sondern selbstverständlich. In Deinem Beispiel wird doch nichts auf stderr geschrieben, oder? Damit geht child_stderr.read() erst zuende, wenn child_stderr geschlossen wird (wenn also klar ist, dass da keine Daten mehr kommen). Die Frage ist nun, ob das print-Kommando im Kindprozess zuende geht oder nicht. print gibt auf stdout aus, aber das ist ja eine Pipe. Dh. das Betriebssystem puffert eine gewisse Menge Daten, aber nicht beliebig viele. Wenn die Pipe "voll" ist, werden weitere Schreibaktionen im Kindprozess blockiert, dh. der Kindprozess terminiert nicht. Der Kindprozess *würde* weiterarbeiten, wenn der Elternprozess aus der Pipe liest. Macht er aber (in test2Popen) nicht: er hängt ja im read auf stderr. Diese Situation nennt man "deadlock": beide Prozesse warten gegenseitig darauf, dass der andere eine bestimmte Aktion ausführt, die der aber nicht ausführen wird. Das Problem ist nicht Windows-spezifisch, nur die Puffergröße ist es. Probier's mal mit 100000 auf Linux; in Linux 2.6. ist die Puffergröße einer Pipe 64k. Es gibt drei traditionelle Lösungsstrategien für dieses Problem: 1) Multi-threading: stdout und stderr werden in separaten Threads gelesen 2) select/poll/WaitForMultipleObjects: anstatt blockierend zu lesen, testet man, von welchem Filedeskriptor gelesen werden kann 3) "Protokolle": zwischen Elternprozess und Kindprozess wird ein Regime festgelegt, bei dem der Pipe-Puffer nicht vollaufen kann (weil beide immer synchron lesen und schreiben). Diese Phänomene sind in jedem guten Buch über Betriebssysteme erläutert. Ciao, Martin _______________________________________________ python-de maillist - python-de@python.net http://python.net/mailman/listinfo/python-de
participants (2)
-
"Martin v. Löwis"
-
Rauch, Juergen (Juergen)