2011-07-03 4 views
14

Envío de objetos simples entre procesos que utilizan tuberías con el módulo de multiprocesamiento de Python. La documentación indica que si se ha cerrado un conducto, al llamar a pipe.recv() debería aparecer EOFError. En cambio, mi programa simplemente está bloqueando en recv() y nunca detecta que la tubería se ha cerrado.¿Por qué no pipe.close() causa EOFError durante pipe.recv() en el multiproceso de python?

Ejemplo:

import multiprocessing as m 

def fn(pipe): 
    print "recv:", pipe.recv() 
    print "recv:", pipe.recv() 

if __name__ == '__main__': 
    p1, p2 = m.Pipe() 
    pr = m.Process(target=fn, args=(p2,)) 
    pr.start() 

    p1.send(1) 
    p1.close() ## should generate EOFError in remote process 

Y la salida será similar a:

recv: 1 
<blocks here> 

Puede alguien decirme lo que estoy haciendo mal? Tengo este problema en Linux y Windows/cygwin, pero no con Windows Python.

Respuesta

8

El proceso bifurcado (secundario) hereda una copia de los descriptores de archivos de sus elementos principales. Por lo tanto, aunque el padre llame "cerrar" en p1, el niño todavía tiene una copia abierta y el objeto kernel subyacente no se está liberando.

Para el montaje, es necesario cerrar el lado "escritura" de la tubería en el niño, así:

def fn(pipe): 
    p1.close() 
    print "recv:", pipe.recv() 
    print "recv:", pipe.recv() 
+1

Por supuesto, esto es correcto, pero el propósito de la pregunta es determinar por qué el cierre de tubería no se comunica entre el proceso primario y secundario, como ocurre en Windows (y como la documentación sugiere que debería). – Luke

+1

Ok, al volver a examinar, tiene toda la razón (y no entendí correctamente su respuesta). La tubería no se considera 'cerrada' hasta que todos los procesos que utilizan el descriptor de archivo la hayan cerrado. – Luke

+0

Una consecuencia interesante/incómoda de esto es que es necesario enviar ambos extremos de la tubería a procesos secundarios para que puedan cerrar uno de manera explícita. – Luke

2

De this solution he observado que os.close(pipe.fileno()) podría romper inmediatamente el tubo donde pipe.close() no ocurre hasta que todos los procesos/subprocesos finalizan. Puedes intentar eso en su lugar. Advertencia: No puede usar pipe.close() después, pero las imágenes fijas pipe.closed devuelven "false". Entonces puede hacer esto para estar más limpio:

os.close(pipe.fileno()) 
pipe=open('/dev/null') 
pipe.close() 
Cuestiones relacionadas