Страницы

Поиск по вопросам

среда, 5 февраля 2020 г.

Почему пример из документации, для модуля multiprocessing не работает в репл?

#python #python_3x


Открываю документацию по модулю, копирую второй пример в IDE:

from multiprocessing import Process

def f(name):
    print('hello', name)

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()


И получаю вот такой результат:

>>> Traceback (most recent call last):
  File "", line 1, in 
  File "C:\Python36\lib\multiprocessing\spawn.py", line 105, in spawn_main
    exitcode = _main(fd)
  File "C:\Python36\lib\multiprocessing\spawn.py", line 115, in _main
    self = reduction.pickle.load(from_parent)
AttributeError: Can't get attribute 'f' on 


Тоже самое происходит и в стандартной IDLE, подскажите в чем может быть проблема?

нашел частичное решение, если вместо multiprocessing использовать multiprocessing.dummy,
то кое-что работает, однако все-равно не ясно из за чего это происходит
    


Ответы

Ответ 1



Модуль со скриптом (который процессы создаёт) обязан безопасно импортироваться без запуска новых процессов при использовании spawn (по умолчанию на Windows), forkserver методов запуска. См. пример в документации: Safe importing of main module. Обычно, достаточно if __name__ == '__main__' защиту использовать для частей, которые новые процессы создают. В интерактивном интерпретаторе и в модулях, которые как скрипты выполняются: __name__ == '__main__', поэтому могут ошибки возникать. Когда вы успешно импортируете f из другого модуля, он не будет назван __main__, поэтому может не возникнуть ошибка (успешный pickle). Подробнее: для запуска нового процесса, вам нужна функция f чтобы запустить функцию f, Питон должен импортировать модуль её содержащий. В новом процессе у вас ничего нет, кроме встроенных имён. Всё остальное явно импортируется если модуль назван __main__ (скрипт или интерактивный случай), то при импорте if __name__ == '__main__' выполняется и вы пытаетесь рекурсивно ещё новые процессы запустить (fork bomb). В реализации multiprocessing могут некоторые ухищрения присутствовать, чтобы вместо fork bomb исключение возникло (лучше) если модуль не назван __main__, то нет проблем с его импортом. В зависимости от особенностей реализации multiprocessing, текущего окружения, может быть достаточно, если f является pickable (глобальная функция из модуля, который можно импортировать, попадает в эту категорию) multiprocessing.dummy может работать так как в этом случае создаются новые потоки, а не процессы (все данные общие: глобальная переменная f во всех потоках доступна).

Ответ 2



Для понимания, может вот такой пример поможет: from multiprocessing import Process from time import sleep class A: def __call__(self, count=10, sleep_time=0.5): for i in range(count): print('Working class A, i=%s' % i) sleep(sleep_time) class B: def __call__(self, count=10, sleep_time=0.5): for i in range(count): print('Working class B, i=%s' % i) sleep(sleep_time) if __name__ == '__main__': a = A() b = B() p1 = Process(target=a, kwargs={'sleep_time': 0.7}) p2 = Process(target=b, args=(12,)) p1.start() p2.start() p1.join() p2.join()

Ответ 3



Как ни странно, работает, если разнести пример в два модуля: example1.py def f(name): print('hello', name) example2.py from multiprocessing import Process from example1 import * if __name__ == '__main__': p = Process(target=f, args=('bob',)) p.start() p.join() Внес изменения, спасибо за уточнение в коментах.

Комментариев нет:

Отправить комментарий