2012-05-02 10 views
18

Ho ereditato un codice che è periodicamente (casualmente) in mancanza a causa di un errore di input/output viene sollevata durante una chiamata per la stampa. Sto cercando di determinare la causa dell'eccezione (o almeno, meglio capirla) e come gestirla correttamente.IOError Input/Output degli errori durante la stampa

Quando si esegue la seguente riga di Python (in 2.6.6 interprete, in esecuzione su CentOS 5.5):

print >> sys.stderr, 'Unable to do something: %s' % command 

L'eccezione viene sollevata (traceback omesso):

IOError: [Errno 5] Input/output error 

Per contesto , questo è generalmente ciò che la funzione più grande sta tentando di fare al momento:

from subprocess import Popen, PIPE 
import sys 
def run_commands(commands): 
    for command in commands: 
     try: 
      out, err = Popen(command, shell=True, stdout=PIPE, stderr=PIPE).communicate() 
      print >> sys.stdout, out 
      if err: 
       raise Exception('ERROR -- an error occurred when executing this command: %s --- err: %s' % (command, err)) 
     except: 
      print >> sys.stderr, 'Unable to do something: %s' % command 
run_commands(["ls", "echo foo"]) 

La sintassinon mi è particolarmente familiare, non è qualcosa che uso spesso, e capisco che è forse lo least preferred way di scrivere su stderr. Tuttavia, non credo che le alternative possano risolvere il problema sottostante.

Dalla documentazione che ho letto, IOError 5 è spesso in modo abusivo, e un po 'vagamente definito, con i diversi sistemi operativi che utilizzano per coprire problemi diversi. Il meglio che posso vedere nel mio caso è che il processo python non è più collegato al terminale/pty.

Come meglio posso dire che nulla sta disconnettendo il processo dai flussi stdout/stderr - il terminale è ancora aperto per esempio, e tutto 'sembra' va bene. Potrebbe essere causato dal processo figlio che termina in modo impuro? Cos'altro potrebbe essere una causa di questo problema - o quali altri passi potrei introdurre per eseguire il debugging ulteriormente?

In termini di gestione dell'eccezione, posso ovviamente prenderlo, ma suppongo che questo significhi che non sarò in grado di stampare su stdout/stderr per il resto dell'esecuzione? Posso riattaccare a questi flussi in qualche modo, magari ripristinando sys.stdout a sys.__stdout__ ecc.? In questo caso non essere in grado di scrivere su stdout/stderr non è considerato fatale, ma se è un'indicazione di qualcosa che sta iniziando a sbagliare preferirei una cauzione anticipata.

Credo che in ultima analisi, sono a un po 'di una perdita da dove iniziare il debug questo ...

+1

posso vedere solo poche persone hanno visitato questa domanda, senza commenti/risposte. Se la domanda è scarsamente strutturata/non chiara, ti prego di aiutarmi a migliorarla in modo che possa lavorare per una risposta. –

+0

Sto anche espirando questo errore. Così fastidioso per ottenere questo errore a volte. –

+1

Non ti preoccupare per poche risposte; la tua domanda e il tuo formato sono fantastici; questa è semplicemente una domanda difficile a cui rispondere. – culix

risposta

5

Ho avuto un problema molto simile. Ho avuto un programma che stava lanciando diversi altri programmi utilizzando il modulo subprocess. Questi sottoprocessi avrebbero quindi stampato l'output sul terminale. Quello che ho scoperto è che quando ho chiuso il programma principale, non ha terminato automaticamente i sottoprocessi (come avevo ipotizzato), ma hanno continuato a funzionare. Quindi, se avessi terminato sia il programma principale che il terminale che era stato lanciato da *, i sottoprocessi non avevano più un terminale collegato al loro stdout e avrebbero lanciato un IOError. Spero che questo ti aiuti.

* NB: deve essere eseguito in questo ordine. Se semplicemente uccidi il terminale, (per qualche motivo) questo ucciderebbe sia il programma principale che i sottoprocessi.

+1

Ciò che descrivi ha senso per la mia situazione, tuttavia rimane una domanda. Secondo i documenti, la chiamata a communicate() dovrebbe essere letta fino al raggiungimento della fine del file e attendere il termine del sottoprocesso. Dato che sto ottenendo questo errore durante l'esecuzione normale (sto lasciando che sia il processo genitore che quello figlio terminino naturalmente) vuol dire che comunicare() sta tornando presto? –

2

Ho appena ricevuto questo errore perché la directory in cui stavo scrivendo i file ha esaurito la memoria. Non sono sicuro se questo è del tutto applicabile alla tua situazione.

+0

No, sfortunatamente no. Un sacco di spazio su disco disponibile, apparentemente non raggiungendo il limite massimo di handle di file, carico di CPU basso e nessuno scambio. –

10

Penso che abbia a che fare con il terminale a cui è collegato il processo.Ho ottenuto questo errore quando ho eseguito un processo di pitone in background e chiuso il terminale in cui ho iniziato:

$ myprogram.py 
Ctrl-Z 
$ bg 
$ exit 

Il problema era che ho iniziato un processo non daemonized in un server remoto e disconnesso (chiusura della sessione terminale). Una soluzione era avviare una sessione screen/tmux sul server remoto e avviare il processo all'interno di questa sessione. Quindi, staccando la sessione + logout, il terminale viene associato al processo. Questo funziona almeno nel mondo * nix.

0

potrebbe accadere quando si blocca il guscio mentre la stampa stava cercando di scrivere i dati in esso.

0

Sono nuovo qui, quindi per favore perdoni se mi infilo un po 'quando si tratta di codice di dettagli. Recentemente sono stato in grado di capire ciò che causa l'errore di I/O della dichiarazione di stampa quando il terminale associato con la corsa dello script python è chiuso. È perché la stringa da stampare su stdout/stderr è troppo lunga. In questo caso, la stringa "out" è il colpevole. Per risolvere questo problema (senza dover tenere il terminale aperto durante l'esecuzione dello script python), è sufficiente leggere il "fuori" linea di corda per riga, e linea di stampa per riga, fino a raggiungere la fine del "fuori" stringa. Qualcosa di simile:

while true: 
     ln=out.readline() 
     if not ln: break 
     print ln.strip("\n") # print without new line 

Lo stesso problema si verifica se si stampa l'intero elenco di stringhe sullo schermo. Basta stampare l'elenco di un articolo per articolo. Spero che questo aiuti!