Python 3.6+: вложенные многопроцессорные менеджеры вызывают FileNotFoundError - PullRequest
1 голос
/ 18 июня 2019

Итак, я пытаюсь использовать диспетчер многопроцессорной обработки по требованию, это была моя первоначальная попытка:

from multiprocessing import Process, Manager

def task(stat):
    test['z'] += 1
    test['y']['Y0'] += 5


if __name__ == '__main__':
    test = Manager().dict({'x': {'X0': 10, 'X1': 20}, 'y': {'Y0': 0, 'Y1': 0}, 'z': 0})

    p = Process(target=task, args=(test,))
    p.start()
    p.join()

    print(test)

Конечно, когда я запускаю это, вывод не соответствует ожиданиям, z корректно обновляется, пока y не изменяется!Это вывод:

{'x': {'X0': 10, 'X1': 20}, 'y': {'Y0': 0, 'Y1': 0}, 'z': 1}

Тогда я гуглил и нашел объяснение здесь , очевидно, вложенные dicts должны быть Manager().dict() s, а не обычные python (возможно, так какPython 3.6).Поэтому я сделал следующее:

from multiprocessing import Process, Manager

def task(stat):
    test['z'] += 1
    test['y']['Y0'] += 5


if __name__ == '__main__':
    test = Manager().dict({'x': Manager().dict({'X0': 10, 'X1': 20}), 'y': Manager().dict({'Y0': 0, 'Y1': 0}), 'z': 0})

    p = Process(target=task, args=(test,))
    p.start()
    p.join()

    print(test)
    print(test['y'])

Но вместо того, чтобы он работал должным образом, я получаю эту необъяснимую ошибку (ошибки), разделенную на три части для ясности.Первая часть соответствует test['y']['Y0'] += 5, а вторая - просто print(test), а последняя - выводу print(test['y'])

Process Process-4:
Traceback (most recent call last):
  File "/usr/lib/python3.7/multiprocessing/process.py", line 297, in _bootstrap
    self.run()
  File "/usr/lib/python3.7/multiprocessing/process.py", line 99, in run
    self._target(*self._args, **self._kwargs)
  File "shit.py", line 5, in task
    test['y']['Y0'] += 5
  File "<string>", line 2, in __getitem__
  File "/usr/lib/python3.7/multiprocessing/managers.py", line 796, in _callmethod
    kind, result = conn.recv()
  File "/usr/lib/python3.7/multiprocessing/connection.py", line 251, in recv
    return _ForkingPickler.loads(buf.getbuffer())
  File "/usr/lib/python3.7/multiprocessing/managers.py", line 920, in RebuildProxy
    return func(token, serializer, incref=incref, **kwds)
  File "/usr/lib/python3.7/multiprocessing/managers.py", line 770, in __init__
    self._incref()
  File "/usr/lib/python3.7/multiprocessing/managers.py", line 824, in _incref
    conn = self._Client(self._token.address, authkey=self._authkey)
  File "/usr/lib/python3.7/multiprocessing/connection.py", line 492, in Client
    c = SocketClient(address)
  File "/usr/lib/python3.7/multiprocessing/connection.py", line 619, in SocketClient
    s.connect(address)
FileNotFoundError: [Errno 2] No such file or directory




{'x': <DictProxy object, typeid 'dict' at 0x7f01de2c5860>, 'y': <DictProxy object, typeid 'dict' at 0x7f01de2c5898>, 'z': 1}




Traceback (most recent call last):
  File "test.py", line 16, in <module>
    print(test['y'])
  File "<string>", line 2, in __getitem__
  File "/usr/lib/python3.7/multiprocessing/managers.py", line 796, in _callmethod
    kind, result = conn.recv()
  File "/usr/lib/python3.7/multiprocessing/connection.py", line 251, in recv
    return _ForkingPickler.loads(buf.getbuffer())
  File "/usr/lib/python3.7/multiprocessing/managers.py", line 920, in RebuildProxy
    return func(token, serializer, incref=incref, **kwds)
  File "/usr/lib/python3.7/multiprocessing/managers.py", line 770, in __init__
    self._incref()
  File "/usr/lib/python3.7/multiprocessing/managers.py", line 824, in _incref
    conn = self._Client(self._token.address, authkey=self._authkey)
  File "/usr/lib/python3.7/multiprocessing/connection.py", line 492, in Client
    c = SocketClient(address)
  File "/usr/lib/python3.7/multiprocessing/connection.py", line 619, in SocketClient
    s.connect(address)
FileNotFoundError: [Errno 2] No such file or directory

Я не уверен, почему это происходит.Внутренние диктанты, очевидно, создаются (как показано во второй части вывода).Но по какой-то причине их вообще нельзя читать или писать!Почему это происходит?

Дополнительно: Если я запускаю тот же код Python через консоль Python (а не через скрипт), ошибка изменяется с FileNotFoundError на ConnectionRefusedError.Но с точно такой же трассировкой!

1 Ответ

2 голосов
/ 18 июня 2019

С Manager() в Manager().dict() вы каждый раз запускаете новый процесс менеджера, поэтому вы действительно вкладываете менеджеров (как говорится в названии), и это не так, как должно быть.Вместо этого вам нужно создать экземпляр one Manager и затем создать словари для этого экземпляра менеджера:

from multiprocessing import Process, Manager
from multiprocessing.managers import DictProxy


def task(test):  # use parameter `test`, else you rely on forking
    test['z'] += 1
    test['y']['Y0'] += 5


if __name__ == '__main__':

    with Manager() as m:

        test = m.dict({'x': m.dict({'X0': 10, 'X1': 20}),
                       'y': m.dict({'Y0': 0, 'Y1': 0}),
                       'z': 0})

        p = Process(target=task, args=(test,))
        p.start()
        p.join()

        print(test)
        print(test['y'])

        # convert to normal dict before closing manager for persistence
        # in parent or for printing dict behind proxies
        d = {k: dict(v) if isinstance(v, DictProxy) else v
             for k, v in test.items()}

    print(d) # Manager already closed here

Пример вывода:

{'x': <DictProxy object, typeid 'dict' at 0x7f98cdaaa588>, 'y': <DictProxy object, typeid 'dict' at 0x7f98cda99c50>, 'z': 1}
{'Y0': 5, 'Y1': 0}
{'x': {'X0': 10, 'X1': 20}, 'y': {'Y0': 5, 'Y1': 0}, 'z': 1}

Process finished with exit code 0

Вы такженеобходимо использовать Manager.Lock на случай, если вы планируете модифицировать объекты manager из нескольких процессов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...