MultiProcessing Pipe recv блокирует даже когда дочерний процесс не функционирует
Читая несколько вопросов по этой теме, я теперь понимаю, что дочерний процесс наследует файловые дескрипторы от родительского процесса. Что затруднит получение ребенком EOFError, когда родитель закрывает соединение.
Но у меня ситуация наоборот, и я не понимаю проблемы, с которой сталкиваюсь.
У меня есть родительский процесс, который запускает дочерний процесс и дает ему доступ к одному концу созданного мной соединения Pipe. Теперь, когда дочерний процесс завершен, неисправности или что-то еще, все останавливается и соединение закрывается. На этом этапе дочерний процесс показывает, что он больше не функционирует.
Затем я ожидаю, что соединение родительского процесса вызовет EOFError в блокирующем вызове recv. Но вместо этого он просто сидит и ждет.
Что мне здесь не хватает?
РЕДАКТИРОВАТЬ
Я думаю, что этот пример представляет проблему:
from multiprocessing import Process, Pipe
from threading import Thread
import time
class Parent(object):
def __init__(self):
self.parent_conn, child_conn = Pipe()
self.child = Process(target=Child, args=(child_conn,))
self.child.start()
def recv():
try:
self.parent_conn.recv()
except EOFError:
print "EOF"
except:
print "something else"
# Does not work
recv()
# Works fine
t = Thread(target=recv)
t.setDaemon(True)
t.start()
def close(self):
self.parent_conn.close()
self.child.join()
class Child(object):
def __init__(self, conn):
conn.close()
if __name__ == "__main__":
p = Parent()
time.sleep(1)
p.close()
Если я использую отдельный поток, родитель может закрывать собственное соединение, и все работает нормально. (Обратите внимание, что вам все равно нужно каким-то образом знать, для чего сделан дочерний процесс, для этого) Вместо этого, если я вызову recv напрямую, он явно заблокируется, но я подозреваю, что он вызовет EOFError, как только дочерний процесс закроет свое соединение. Но это не так. Кто-нибудь может уточнить?
1 ответ
Добавлять child_conn.close()
после self.child.start()
, Идиоматично для работы с трубами закрывать неиспользуемые концы. Также (опционально) предоставляем duplex=False
параметр.
Дело в том, что я не знаю заранее, собирается ли он закрыться сразу же. Обычно ребенок должен иметь возможность отправлять и получать. Кроме того, я до сих пор не понимаю, почему это не будет работать, как есть.
child_conn.close()
в родительском не означает, что ребенок должен закрыть свой конец немедленноparent_conn.recv
не возвращается, пока не появится шанс, что кто-тоchild_conn.send()
, Еслиchild_conn
открывается (в дочернем или родительском), то есть шанс
Если я использую отдельный поток, родитель может закрывать собственное соединение, и все работает нормально. Обратите внимание, что вам все равно нужно как-то знать, для чего сделан ребенок, чтобы сделать это
Вам не нужно это знать. Вы можете закрыть, как только у ребенка открывается соединение. призвание child_conn.close()
в родительском после self.child.start()
хорошо, что бы ни делал ребенок.
Не могли бы вы также объяснить немного дуплекс?
duplex = False означает, что канал является однонаправленным, т.е. вы можете только parent_conn.recv()
а также child_conn.send()
, В противном случае он является двунаправленным, и оба соединения поддерживают отправку / запись.