Python 3.6.8 — многопроцессорная обработка.Pool.apply_async() не работает

#python #multiprocessing

Вопрос:

Похоже, что apply_async не работает, и ничего не происходит. Не знаю, что здесь не так. Я использую macOS catalina

 import time from multiprocessing import Pool  def worker(sl):  print(sl)  time.sleep(sl)  return sl  if __name__ == '__main__':  with Pool(processes=3) as pool:  for i in range(5,30,5):  result = pool.apply_async(func=worker,args=(i,))  

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

1. какую среду разработки вы используете? не все IDE правильно обрабатывают инструкции печати из дочерних процессов. Spyder, например, только что улучшил поддержку в 5.2.0, вы также перезаписываете result и сохраняете только последнюю…

2. Я использую версию кода Visual Studio: 1.61.2

3. попробуйте запустить свой код с терминала (или cmd в Windows).

4. Я бы также рекомендовал обновить python по крайней мере до 3.9, если вы действительно хотите начать использовать multiprocessing (если ваш проект позволяет это). Начиная с версии 3.6 было выпущено несколько важных обновлений и исправлений

Ответ №1:

Когда вы звоните pool.apply_async , вы планируете выполнение задачи. Возвращаемое значение этого вызова-это multiprocessing.pool.AsyncResult экземпляр, для которого вы вызываете метод get , который будет заблокирован до завершения задачи и вернет возвращаемое значение из рабочей функции, указанной в apply_async вызове метода. Но вы не звонили get (или wait ) ни в один из этих AsyncResult случаев. Вместо этого вы позволили себе немедленно провалиться в конец with Pool(processes=3) as pool: блока, и в этом заключается ваша проблема.

Документация не очень ясна. Однако есть такое предупреждение:

Внимание: multiprocessing.pool у объектов есть внутренние ресурсы, которыми необходимо правильно управлять (как и любым другим ресурсом), используя пул в качестве контекстного менеджера или вызывая close() и terminate() вручную. Невыполнение этого требования может привести к зависанию процесса доработки.

Вы используете пул в качестве контекстного менеджера в результате выполнения with инструкции, и на самом деле происходит то, что при завершении with блока происходит вызов pool.terminate() . Таким образом, все процессы в пуле немедленно завершаются до того, как у них появится возможность выполнить любую из представленных вами задач.

Поскольку вас не интересуют фактические возвращаемые значения worker , альтернативой сохранению AsyncResult объектов и вызову get их является вызов pool.close() , за которым следует pool.join() перед выходом из with блока, который будет ждать завершения всех отправленных задач.:

close() Предотвращает отправку в пул новых задач. Как только все задачи будут выполнены, рабочие процессы завершатся.

join() Дождитесь завершения рабочих процессов. Необходимо позвонить close() или terminate() перед использованием join() .

 import time from multiprocessing import Pool  def worker(sl):  print(sl)  time.sleep(sl)  return sl  if __name__ == '__main__':  with Pool(processes=3) as pool:  for i in range(5,30,5):  result = pool.apply_async(func=worker,args=(i,))  pool.close()  pool.join()  

С принтами:

 5 10 15 20 25