2016-06-06 3 views
1

TLDR: steckte mit dieser https://code.google.com/archive/p/byte-unixbench/issues/1Subproces.popen - Slave-Schreibvorgang fehlgeschlagen: Defekte Pipe; Abbruch

Versuch UnixBench mit subprocess.popen() während der Aufnahme Ausgabe und Drucken Sie es aus in Echtzeit ausgeführt werden.

Dies ist das Unterprogramm I habe kommen mit:

def run_and_print(command, cwd=None, catch_stderr = False): 
    if catch_stderr: 
     err_pipe = subprocess.PIPE 
    else: 
     err_pipe = subprocess.STDOUT 

    p = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=1, cwd=cwd, stderr=err_pipe) 
    r = '' 
    while True: 
     if catch_stderr: 
      out = p.stderr.read(1) 
     else: 
      out = p.stdout.read(1) 
     if out == "" and p.poll() != None: 
      break 
     sys.stdout.write(out) 
     sys.stdout.flush() 
     r += out 

    return r 

Es funktioniert gut für alle Zwecke mit Ausnahme UnixBench. Unixbench stirbt nur nach einer Weile:

unixbench = run_and_print(['./Run']) 

...

1 x Rohrdurchsatz 1 2 3 4 5 6 7 8 9 10

1 x Rohrbasierte Kontextumschaltung 1 2 3 4


Run: "Pipe basierte Kontextumschaltung": Slave schreiben versagt: Unterbrochenes Rohr; abbrechen

Google hat nicht viel geholfen. Das einzige aussagekräftige Ergebnis, das ich habe, ist https://code.google.com/archive/p/byte-unixbench/issues/1 und ich schlage vor, dass die Lösung zum Erstellen einer Java-App für mich nicht funktioniert, da ich das Skript mit so wenigen Abhängigkeiten wie möglich ausführen muss.

Ich werde für jede Lösung oder eine Problemumgehung dankbar sein. Das System, das ich auf die Prüfung dieses bin ist Ubuntu 14.04.4 x64

+0

Wahrscheinlich wird nicht helfen, aber haben Sie versucht, 'p.communicate()'?Ein möglicher Hack: Versuchen Sie nicht, die Ausgabe in Python zu erfassen; Führen Sie stattdessen den Befehl aus, indem Sie stderr und stdout in verschiedene Textdateien umleiten. Dann lies diese Dateien über Python. – FMc

+0

@FMc Gute Idee über das Schreiben in Dateien, nicht sicher, wie stdout in Echtzeit drucken, wenn es in eine Datei umgeleitet wird. Wie empfehlen Sie die Verwendung von p.communicate()? Es war mein Verständnis, dass ich mit "kommunizieren" keine Ausgabe erhalten werde, bis der Prozess abgeschlossen ist. Danke für die Antwort. – Anton

+1

@ user1556912, Ihr Verständnis ist richtig, Sie können nicht kommunizieren, wenn Sie die Ausgabe sofort wollen. –

Antwort

2

Der Fehler zu 'yes' reporting error with subprocess communicate() verwandt ist, die das Update bietet: reenable SIGPIPE Signal im Kindprozess preexec_fn (oder verwenden Python 3).


Unrelated: Ihr Code kann Deadlock wenn catch_stderr wahr ist und p.stderr und p.stdout sind nicht perfekt synchron.

Ansonsten catch_stderr hat keine Wirkung (Pufferung ignorieren): Ihr Code erfasst stderr unabhängig. Man könnte es vereinfachen:

#!/usr/bin/env python 
from shutil import copyfileobj 
from subprocess import Popen, PIPE, STDOUT 

def run_and_print(command, cwd=None): 
    p = Popen(command, stdout=PIPE, stderr=STDOUT, bufsize=-1, cwd=cwd, 
       preexec_fn=restore_signals) 
    with p.stdout: 
     tee = Tee() 
     copyfileobj(p.stdout, tee)   
    return p.wait(), tee.getvalue() 

wo Tee() ein dateiähnliche Objekt ist, das an zwei Stellen schreibt: stdout und StringIO():

import sys 
from io import BytesIO 

class Tee: 
    def __init__(self): 
     self.file = BytesIO() 
    def write(self, data): 
     getattr(sys.stdout, 'buffer', sys.stdout).write(data) 
     self.file.write(data) 
    def getvalue(self): 
     return self.file.getvalue() 

wo restore_signals() is defined here.


Wenn Sie die Ausgabe auf dem Bildschirm sehen möchten, sobald der Befehl sie druckt; Sie könnten Tee, copyfileobj() und use os.read(), Inlines die komplette length, bevor es zu stdout zu vermeiden Lesen Schreiben:

chunks = [] 
with p.stdout: 
    for chunk in iter(lambda: os.read(p.stdout.fileno(), 1 << 13), b''): 
     getattr(sys.stdout, 'buffer', sys.stdout).write(chunk) 
     sys.stdout.flush() 
     chunks.append(chunk) 
return p.wait(), b''.join(chunks) 

den internen Block-Buffering in den untergeordneten Prozess zu deaktivieren, können Sie zu run it using stdbuf or pass pseudo-tty instead of the pipe versuchen.

+0

Vielen Dank für all Ihre Vorschläge! Werde mich melden sobald ich sie getestet habe. Da catch_stderr keine Wirkung hat, starte ich manchmal Befehle, die auf 'stderr' statt auf' stdout' ('dd' als Beispiel) drucken. Ich werde sehen, ob dein Code das auch löst. Vielen Dank. – Anton

+0

Ich kann bestätigen, dass 'preexec_fn' das Problem mit dem UnixBench behoben hat. Es beendet alle Benchmarks erfolgreich. Allerdings konnte ich nicht Ihre Version mit 'Tee' in Echtzeit ausgeben (so wie die ursprüngliche Funktion funktionierte), aber ich konnte meinen Code ändern, um zu arbeiten. Ich muss immer noch einen Weg finden, um das mögliche Deadlock-Problem zu lösen, auf das Sie hingewiesen haben. Danke nochmal! Du bist der beste! – Anton

+0

Oh, und ich habe Ihr Update zu spät bemerkt. Danke für die Implementierung der Echtzeitausgabe. Werde es heute Abend versuchen! SO muss "senden Sie ein Bier" Knopf implementieren :) – Anton

Verwandte Themen