6.8.2 Problemi con il controllo di flusso

Ogni volta che lavorate con qualche forma di comunicazione tra i processi, il controllo di flusso deve venire attentamente considerato. Questo è anche il caso con i file oggetto forniti da questo modulo (o con i suoi equivalenti nel modulo os).

Quando viene letto l'output di un sotto processo che scrive molti dati sullo standard error mentre il processo padre è occupato a leggerne i dati sullo standard output, si può verificare una situazione di blocco reciproco (deadlock). Una situazione simile può accadere con altre combinazioni di lettura/scrittura. Le cause essenziali di queste situazioni sono che da un lato un processo tenta di scrivere, in modo bloccante, più bytes di quanti ne può contenere il buffer (_PC_PIPE_BUF), mentre dall'altro lato, l'altro processo sta tentanto di leggere dati su un'altro canale, sempre in modo bloccante.

Esistono diversi metodi per gestire questa situazione.

Il modo più semplice di adattare l'applicazione, in molti casi, sarà quello di seguire il seguente modello nel processo padre:

import popen2

r, w, e = popen2.popen3('python slave.py')
e.readlines()
r.readlines()
r.close()
e.close()
w.close()

con codice come questo nel processo figlio:

import os
import sys

# notate che ciascuna delle istruzioni di stampa
# scrive una singola lunga linea

print >>sys.stderr, 400 * 'this is a test\n'
os.close(sys.stderr.fileno())
print >>sys.stdout, 400 * 'this is another test\n'

In particolare notate che sys.stderr va chiuso dopo aver scritto tutti i dati, oppure readlines() non terminerà. Notate anche che va usato os.close(), in quanto sys.stderr.close() non chiude il canale dello stderr (altrimenti riassegnare sys.stderr ne provocherebbe l'implicita chiusura, impedendo la stampa di ulteriori errori ).

Applicazioni che hanno la necessità di supportare un approccio più generale, dovrebbero integrare nel loro ciclo di select(), l'input/output sui canali input/output/error dei processi figli, oppure usare thread separati per leggere ciascuno dei file forniti da qualsivoglia funzione popen*() o classe Popen* essi usino.

Vedete Circa questo documento... per informazioni su modifiche e suggerimenti.