2011-07-03 10 views
14

Wysyłam proste obiekty między procesami za pomocą potoków z modułem wieloprocesorowym Pythona. Dokumentacja stwierdza, że ​​jeśli rura została zamknięta, wywołanie metody pipe.recv() powinno spowodować podniesienie EOFError. Zamiast tego, mój program właśnie blokuje recv() i nigdy nie wykrywa, że ​​rura została zamknięta.Dlaczego pipe.close() nie powoduje EOFError podczas pipe.recv() w wieloprocesorowym pythonie?

Przykład:

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 

a wyjście wygląda następująco:

recv: 1 
<blocks here> 

Czy ktoś może mi powiedzieć co robię źle? Mam ten problem w Linuksie i Windows/cygwin, ale nie z rodzimym językiem Pythona.

Odpowiedz

8

Proces rozwidlony (potomek) dziedziczy kopię deskryptorów plików nadrzędnych. Tak więc nawet jeśli rodzic nazywa "zamknij" na p1, dziecko nadal ma otwartą kopię i bazowy obiekt jądra nie jest zwalniany.

Aby naprawić, trzeba zamknąć „write” stronie rury u dziecka, tak jak poniżej:

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

Oczywiście jest to poprawne, ale celem tego pytania jest ustalenie, dlaczego zamknięcie rurki nie jest przekazywane między procesem nadrzędnym i podrzędnym, tak jak ma to miejsce w systemie Windows (i jak sugeruje dokumentacja). – Luke

+1

OK, po ponownym zbadaniu, masz całkowitą rację (i nie zrozumiałem poprawnie twojej odpowiedzi). Rura nie jest uważana za zamkniętą, dopóki wszystkie procesy korzystające z deskryptora pliku go nie zamkną. – Luke

+0

Ciekawym/niezręcznym skutkiem tego jest konieczność wysłania obu końców potoku do procesów potomnych, aby można je było jednoznacznie zamknąć. – Luke

2

Od this solution ja zauważył, że os.close(pipe.fileno()) mógł natychmiast przerwać potoku gdzie pipe.close() nie kończy się, dopóki nie zakończą się wszystkie procesy/podprocesy. Zamiast tego możesz spróbować. Ostrzeżenie: Nie można użyć pipe.close() po, ale shut.closed nadal zwracają "false". Więc możesz to zrobić, aby być czystszym:

os.close(pipe.fileno()) 
pipe=open('/dev/null') 
pipe.close() 
Powiązane problemy