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 параметр.

Дело в том, что я не знаю заранее, собирается ли он закрыться сразу же. Обычно ребенок должен иметь возможность отправлять и получать. Кроме того, я до сих пор не понимаю, почему это не будет работать, как есть.

  1. child_conn.close() в родительском не означает, что ребенок должен закрыть свой конец немедленно
  2. parent_conn.recv не возвращается, пока не появится шанс, что кто-то child_conn.send(), Если child_conn открывается (в дочернем или родительском), то есть шанс

Если я использую отдельный поток, родитель может закрывать собственное соединение, и все работает нормально. Обратите внимание, что вам все равно нужно как-то знать, для чего сделан ребенок, чтобы сделать это

Вам не нужно это знать. Вы можете закрыть, как только у ребенка открывается соединение. призвание child_conn.close() в родительском после self.child.start() хорошо, что бы ни делал ребенок.

Не могли бы вы также объяснить немного дуплекс?

duplex = False означает, что канал является однонаправленным, т.е. вы можете только parent_conn.recv() а также child_conn.send(), В противном случае он является двунаправленным, и оба соединения поддерживают отправку / запись.

Другие вопросы по тегам