Subprocess und fließende Ausgabe von stdout

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
Miko

Hi,
ich habe das leidige und schon häufig besprochene Problem mit popen und subprocess eine fließende Ausgabe hinzubekommen.

Ich such jetzt schon gut 3 Stunden aber es scheint einfach keine Lösung zu geben.

Ich habe ein kleines Programm:

Code: Alles auswählen

import time

for i in range(5):
	print i
	time.sleep(0.5)
Dieses will ich ausführen mit einem anderen Python Programm und eine aktuelle mitlaufende Ausgabe erhalten. Später selbstverständlich mit Eingaben zwischendurch etc.

Ich stelle hier auch mal meine Testdatei rein in der alle Codesnippets drinnen sind die ich schon probiert hab. Aber nichts will funktionieren.

Im Forum habe ich mir schon fast sämtliche Beiträge zu subprocess durchgelesen. Leider hat nichts geholfen. (Außer dass ich jetzt weis wo gerold wohnt XD)

Ich benutze Debian Linux und Python 2.4 sowie 2.5 zum testen!

Code: Alles auswählen

while 1:
	line = proc.stdout.readline()	
	if not line: break
	print line,
Das liest man ja sehr häufig funktioniert aber bei mir auch nicht!

Meine Tests:

Code: Alles auswählen

import os
import subprocess
import time
import sys
#import pexpect

proc = subprocess.Popen("python /home/miko/Desktop/python/popen2/testprocess3.py", bufsize=0, shell = True, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)

while 1:
	line = proc.stdout.readline()	
	if not line: break
	print line,

#cmd = "python -u /home/miko/Desktop/python/popen2/testprocess3.py"
#proc = pexpect.spawn(cmd)
#proc.expect(shell_pro

#print "Process starts"
#r, w = os.popen4('python testprocess.py')
#r.readlines()
#cmd = ['python', '-u' ,'/home/miko/Desktop/python/popen2/testprocess.py']


#proc = subprocess.Popen("python /home/miko/Desktop/python/popen2/testprocess3.py", bufsize=0, shell = True, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
#line="dum"
#while line != "":
#	line=proc.stdout.readline()
#	sys.stdout.write(line)


#out=proc.stdout.read()
#proc.stdout.flush()
#sys.stdout.flush()
#print out,
#proc.stdout.flush()
#sys.stdout.flush()

#for line in proc.stdout:
#	proc.stdout.flush(0)
#	print line,

#proc.stdin.close()
#proc.stdout.close()
#proc.stderr.close()

#while True:
#stdout, stderr = proc.communicate()
#print "Ausagabe: ", proc.stdout.read()
#print "Error: ", proc.stderr.read()
#print "Fehler: ", stderr
Schöne Grüße
Miko
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Miko hat geschrieben:ich habe das leidige und schon häufig besprochene Problem mit popen und subprocess eine fließende Ausgabe hinzubekommen.
Hallo Miko!

Das aufgerufene Programm entscheidet, ob es dessen STDOUT buffert oder nicht. Da du Python aufrufst, kannst du es mit dem Parameter "-u" dazu überreden, STDIN und STDOUT nicht zu buffern.

Z.B. so:

Code: Alles auswählen

[sys.executable, "-u", "/home/miko/Desktop/python/popen2/testprocess3.py"]
Beim Aufruf von anderen (Nicht-Python-)Programmen wird es schwieriger bis unmöglich.

mfg
Gerold
:-)

EDIT: kleine Codeänderung
Zuletzt geändert von gerold am Freitag 5. Dezember 2008, 10:15, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Miko

Hi,
danke für die Antwort, allerdings habe ich das auch schon gelesen und es hat keinerlei Auswirkungen.
Wie man in der Testdatei sieht habe ich es ja schon probiert!

Ich will das ganze für Serverprogramme (Gameserver z.B.) machen die die Ausgabe ja ungepuffert ausgeben müssen da sie ja auf unbestimmte Zeit laufen.

Python Programme müssen ja standardgemäß schon ungepuffert sein!

Code: Alles auswählen

while 1: print "test"
läuft ja auch ungepuffert!

Falls jemand eine Idee hat sei sie noch so abstrakt bitte melden denn langsam verzweifel ich an dem Problem.
BlackJack

Dein Beispiel (``while``-Schleife) läuft nicht ungepuffert. Wie kommst Du darauf?

Was genau willst Du denn machen?
Miko

es läuft ungepuffert! es wird zeile für zeile ausgegeben!

Was ich machen will steht ein Beitrag weiter oben bzw. auch im Topic selber.

Quasi Aufgabenstellung:
Ungepufferte Ausgabe eines Unterprozesses mit unbestimmter Laufzeit!
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo Miko!

Ich werfe jetzt einfach mal XMLRPC in die Runde.

http://www.python-forum.de/viewtopic.php?p=56486

Und als absolutes Highlight PyRo: http://pyro.sourceforge.net/

...und gehe davon aus, dass du nicht wirklich "Unterprozesses" meinst. Ein Unterprozess stirbt normalerweise, wenn das Hauptprogramm beendet wird. Ein Server läuft ewig. Ein Client verbindet sich Beispielsweise zum Serverprogramm, gibt die Aufgabe weiter, wartet auf das Ergebnis und gibt die Verbindung wieder auf. Der Client kann eine Aufgabe zum Server abgeben und sich wieder trennen. Wenn der Server mit der Arbeit fertig ist, gibt dieser eine kurze Nachricht an den Client zurück, damit dieser bescheid weiß. (Eventsystem) Usw.

mfg
Gerold
:-)
Zuletzt geändert von gerold am Dienstag 4. September 2007, 16:07, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Miko

hm, sei mir nicht bös aber ich verstehe nicht wie das bei meinem Problem helfen soll :?
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Miko hat geschrieben:hm, sei mir nicht bös aber ich verstehe nicht wie das bei meinem Problem helfen soll :?
Hallo Miko!

Erkläre bitte in wenigen Sätzen was du willst und nicht wie du das Problem lösen würdest. Willst du wirklich nur ein Programm aufrufen und dessen Ausgabe zurück bekommen? Denn dafür hast du bereits eine Lösung. Was willst du wirklich?

Du sprichst von einem Gameserver! Ein Gameserver ist normalerweise ein Serverprogramm und kein kurz aufgerufener Prozess, der sich dann wieder verabschiedet.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
BlackJack

@Miko: Es läuft *nicht* ungepuffert! Die ``print``\s schreiben in eine Ausgabedatei, wenn deren Puffer voll ist, wird der Block weitergereicht und landet bei dem Programm dass die Ausgabe vornimmt. Das kann entweder selber wieder Puffern oder die Ausgabe einfach auf dem Bildschirm wiedergeben.

Wenn Du ungepufferte Kommunikation haben willst, müssen das *beide* Kommunikationspartner unterstützen. Der Leser darf nicht Puffern bzw. in Deinem Fall ist ein Zeilenpuffer erlaubt und der Schreiber muss seinen Puffer nach jeder Zeile rausschreiben. Da fehlt in Deinen Beispielen wohl ein `flush()`.
Miko

Hm okay, ein kleines Beispiel:

Ich habe ein Unterprogramm namens sub.py.
Dieses Programm gibt jede Sekunde eine Zahl auf dem Bildschirm aus und läuft unbegrenzt lange.
Dieses Unterprogramm soll im Hauptprogramm Names main.py aufgerufen werden.
Das Hauptprogramm soll dann die gesamte Ausgabe von sub.py auf dem Bildschirm in Echtzeit und ungepuffert ausgeben.

Das klappt aber leider nicht.
Bei allen Tests wird immer gewartet bis das Unterprogramm wieder beendet ist bevor es weitergeht.

edit:
@ blackjack:
Bei meiner kleinen Whileschleife wartet er ja auch nicht mit der Ausgabe bis sich das Programm beendet. Das gleiche will ich beim Externen Aufruf!
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo Miko!

Ohne Worte... einfach ausprobieren.

server.py:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import sys
import time


def main():
    for i in range(5):
        print "Hallo %i" % i
        sys.stdout.flush()
        time.sleep(1)

if __name__ == "__main__":
    main()
client.py:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import os
import sys
import subprocess


proc = subprocess.Popen(
    (sys.executable, "-u", "server.py"), stdout = subprocess.PIPE, cwd = os.curdir,
)

for line in iter(proc.stdout.readline, ""):
    print "Daten vom Server:", line,
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Miko

Oh man das funktioniert.
Erstmal danke!

Hm ich versteh das Zwar nicht ganz denn beim Unterprogramm bekomme ich ja die Ausgabe in Echtzeit. Was da das Flush zu suchen hat versteh ich nicht. Ich weis wozu es gebraucht wird aber warum es gebraucht wird will mir nicht einleuchten. Ein normales python Programm wartet ja auch nicht auf sein Ende bis es was am Bildschirm ausgibt.

Ich hoffe das ganze funktioniert nun mit den Unterprogrammen die ich aufrufen will (z.B. Gameserver)

Das wäre jetzt das erste mal gewesen dass ich etwas in Python machen will ich es mit python aber nicht hinbekomme. Das hätte micht schon sehr enttäuscht wo es bei mir ganz oben steht meiner Lieblingssprachen!
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Miko hat geschrieben:Hm ich versteh das Zwar nicht ganz denn beim Unterprogramm bekomme ich ja die Ausgabe in Echtzeit. Was da das Flush zu suchen hat versteh ich nicht.
Hallo Miko!

Wenn du in einer Schleife einen Text nach STDOUT schreibst und STDOUT eine Konsole ist, dann wird das Programm von der Konsole gebremst. Warum? Weil die Konsole viel, viel, viel, viel langsamer diesen Text anzeigen kann, als du ihn mit deinem Programm erstellen könntest. Deshalb läuft das Programm, wenn es über die Konsole aufgerufen wird um ein viel-, viel-, viel-, vielfaches langsamer, als wenn du es von einem anderen Programm aus (das die Daten nicht anzeigt) aufrufst.
Wenn du z.B. ein Python-Programm von der Konsole aus aufrufst, dann bekommt das Python-Programm intern mit, dass es nicht buffern soll und schreibt sofort alles nach STDOUT.
Bekommt das Programm aber nicht mit, dass es von einer Konsole aufgerufen wird, dann hält es die Daten so lange zurück, bis der Buffer voll ist oder das Programm beendet wurde. >>Oder bis "sys.stdout.flush()" aufgerufen wird.<<

Wenn du also dein Serverprogramm von einem anderen Programm aus aufrufst, dann wird das Serverprogramm die Ausgabe buffern (um schneller arbeiten zu können), da es ja weiß, dass es nicht von einer Konsole aus aufgerufen wird.

Unter Linux kann man sich mit "pexpect" behelfen, aber unter Windows ist es schwieriger, dem aufgerufenen Programm eine Konsole vorzutäuschen.

Das schlimme dabe ist, dass nicht nur Python so arbeitet. Viele Programmiersprachen unterscheiden automatisch, ob sie von einer Konsole aufgerufen werden, oder nicht. So kommt es, dass man dieses Problem bei vielen Programmen hat.

Ich dachte eigentlich, dass bei Python der Parameter "-u" den "sys.stdout.flush()" überflüssig machen sollte. Aber das tut es bei mir seit Python 2.5 (unter Windows XP) nicht mehr. :K Ich glaube aber zu wissen, dass es schon mal ohne sys.stdout.flush() (nur mit -u) funktioniert hat. :roll:

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Miko

ah okay, danke!

Für mich ist nur Linux interessant nicht Windows!

Kann man dem Programm denn nicht vortäuschen es läuft auf einer Konsole?
Es gibt doch die shell variable in subprocess.Popen

Wisst ihr was darüber?
Miko

hm stimmt mein testprogramm (ein ANSI C programm) bekommt wirklich mit dass es keine Konsole ist:
stdin is not a tty, tty console mode failed
Kann ich ihm keine Konsole vortäuschen?

Wo gibt es eine Dokumentation zu pexcept?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Miko hat geschrieben:Wo gibt es eine Dokumentation zu pexcept?
Auf dessen Homepage.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Miko hat geschrieben:wo ist gerolds beitrag hin???
...habe ihn beim Telefonieren gedankenlos gelöscht. Wollte eigentlich nur den URL zu pexpect hinzufügen. :roll:
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
lunar

gerold hat geschrieben:
Miko hat geschrieben:wo ist gerolds beitrag hin???
...habe ihn beim Telefonieren gedankenlos gelöscht. Wollte eigentlich nur den URL zu pexpect hinzufügen. :roll:
Tja, sowas könnte mir nicht passieren... es hat scheints auch Vorteile, wenn man an 60 Jahre alten Kabeln hängt, und die Verbindung beim Telefonieren sang- und klanglos zusammenbricht ;)
Antworten