2015-08-17 17 views
7

Sto lavorando in Python 3.4, e ho un comportamento che non capisco: se reindirizzamento allo stdout su un file, sono in grado di catturare il testo da processi figlio . Tuttavia, quando reindirizzo a un oggetto file Python, interrompo l'acquisizione di quell'output. Mi piacerebbe una spiegazione del comportamento (seguente).Reindirizzare `sys.stdout` in un file o un buffer

ho:

from multiprocessing import Process 

def worker(): 
    print('forked output') 

def output(): 
    print('redirected') 
    p = Process(target=worker) 
    p.daemon = True 
    p.start() 
    p.join() # wait for subprocess to terminate 
    print('end') 

Il gestore redirect_stdout contesto in Python 3.4 rende afferrando stdout facile (in questo caso).

from contextlib import redirect_stdout 
from sys import stdout 
from tempfile import TemporaryFile 


with TemporaryFile(mode='w+', encoding=stdout.encoding) as buf: 
    with redirect_stdout(buf): 
     output() # the function defined above 
    buf.seek(0) 
    s = buf.read() 
    print('output from TemporaryFile:') 
    print(s) 

posso poi semplicemente chiamare lo script per ottenere il seguente risultato:

$ python stackoverflow.py 
output from TemporaryFile: 
redirected 
forked output 
end 

Questo è esattamente quello che voglio, e funziona bene.

La mia confusione deriva dal fatto che se io se cambio TemporaryFile con TextIOWrapper, il comportamento del mio script cambia.

from io import BytesIO, TextIOWrapper 


with TextIOWrapper(BytesIO(), stdout.encoding) as buf: 
    with redirect_stdout(buf): 
     output() # the function defined at the start 
    buf.seek(0) 
    s = buf.read() 
    print('output from TextIO:') 
    print(s) 

Ora quando chiamo il programma, perdo l'output dal processo biforcuto.

$ python stackoverflow.py 
output from TextIO: 
redirected 
end 

Cosa sta succedendo?

ho il sospetto che il problema ha a che fare con il fatto che l'oggetto TextIOWrapper non ha un descrittore di file, e che os.fork() (usato da multiprocessing) può quindi essere la sostituzione del TextIOWrapper con un altro, ma ammetto po 'di confusione c'è (soprattutto considerando che lo stdout sembra essere un TextIOWrapperconfileno() implementato).

>>> from sys import stdout 
>>> stdout.fileno() 
1 
>>> stdout 
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> 

Grazie per qualsiasi informazione.

+2

Credo che tu sia sulla strada giusta. Non ho abbastanza per pubblicare una risposta, ma penso che sia un problema con i descrittori di file; sys.stdout ha un descrittore a livello di sistema, mentre TextIOWrapper è interno a Python. – Cyphase

+0

@Cyphase Sono quasi sicuro che tu abbia ragione. Il reindirizzamento di 'stdout',' stderr' o 'stdin' è un'operazione a livello di sistema operativo, non un'operazione di python. Funziona su descrittori di file. Un oggetto 'BytesIO' non ha descrittore di file perché è strettamente un blob di byte in memoria. 'TemporaryFile' è la strada da percorrere. Su Linux se crei il file nella directory '/ dev/shm', non colpisce mai un disco effettivamente (anche se, probabilmente, [non si usa'/tmp'] (http://stackoverflow.com/questions/9745281/tmp-vs-dev-SHM-per-temp-file-storage on-linux)). – eestrada

risposta

1

Poiché si utilizza il multiprocessing, è necessario utilizzare lo standard message passing primitives fornito da tale libreria. Non chiamare print() dal sottoprocesso; questo è un design scadente.

Se si sta effettivamente cercando di farlo funzionare con il codice di qualcun altro (non Python), utilizzare subprocess.check_output() o un altro delle funzioni di sottoprocesso.

Problemi correlati