Изучая многопроцессорность Python (из статьи PMOTW ), я хотел бы получить некоторые разъяснения о том, что именно join()
делает этот метод.
В старом руководстве от 2008 года говорится, что без p.join()
вызова в приведенном ниже коде «дочерний процесс будет бездействовать и не завершаться, становясь зомби, которого вы должны убить вручную».
from multiprocessing import Process
def say_hello(name='world'):
print "Hello, %s" % name
p = Process(target=say_hello)
p.start()
p.join()
Я добавил распечатку, PID
а также time.sleep
для проверки, и, насколько я могу судить, процесс завершается сам по себе:
from multiprocessing import Process
import sys
import time
def say_hello(name='world'):
print "Hello, %s" % name
print 'Starting:', p.name, p.pid
sys.stdout.flush()
print 'Exiting :', p.name, p.pid
sys.stdout.flush()
time.sleep(20)
p = Process(target=say_hello)
p.start()
# no p.join()
в течение 20 секунд:
936 ttys000 0:00.05 /Library/Frameworks/Python.framework/Versions/2.7/Reso
938 ttys000 0:00.00 /Library/Frameworks/Python.framework/Versions/2.7/Reso
947 ttys001 0:00.13 -bash
через 20 секунд:
947 ttys001 0:00.13 -bash
Поведение такое же, как и при p.join()
добавлении в конец файла. Python Module of the Week предлагает очень удобочитаемое объяснение модуля ; «Чтобы дождаться, пока процесс завершит свою работу и выйдет, используйте метод join ().», Но похоже, что по крайней мере OS X все равно это делала.
Еще меня интересует название метода. Этот .join()
метод что-нибудь объединяет? Соединяет ли процесс с его концом? Или он просто разделяет имя с собственным .join()
методом Python ?
источник
CPU, Memory resources
данные отделяются от родительского процесса, а затемjoin
снова возвращаются после завершения дочернего процесса?Ответы:
join()
Метод, при использованииthreading
илиmultiprocessing
, не связано сstr.join()
- это на самом деле не конкатенации ничего вместе. Скорее, это просто означает «дождаться завершения этого [потока / процесса]». Имяjoin
используется потому, чтоmultiprocessing
API модуля должен выглядеть так же, какthreading
API модуля, иthreading
модуль используетjoin
для своегоThread
объекта. Использование этого терминаjoin
для обозначения «ждать завершения потока» распространено во многих языках программирования, поэтому Python также просто принял его.Теперь причина, по которой вы видите 20-секундную задержку как с вызовом, так и без него,
join()
заключается в том, что по умолчанию, когда основной процесс готов к выходу, он неявно вызываетjoin()
все запущенныеmultiprocessing.Process
экземпляры. Это не так четко указано вmultiprocessing
документации, как должно быть, но упомянуто в разделе «Рекомендации по программированию »:Вы можете переопределить это поведение, установив
daemon
флаг на ,Process
чтобыTrue
до начала процесса:Если вы это сделаете, дочерний процесс будет завершен, как только завершится основной процесс :
источник
p.daemon=True
было для «запуска фонового процесса, который работает без блокировки выхода основной программы». Но если «процесс демона завершается автоматически до выхода из основной программы», в чем именно его смысл?daemonic
дочернего процесса небезопасно, потому что процесс будет завершен без возможности очистки любых открытых ресурсов, которые у него могут быть ... (продолжение).multiprocessing
API разработан так, чтобы имитироватьthreading
API как можно точнее. Демоническиеthreading.Thread
объекты завершаются сразу после выхода из основного потока, поэтому демоническиеmultiprocesing.Process
объекты ведут себя точно так же.Без него
join()
основной процесс может завершиться раньше, чем дочерний процесс. Я не уверен, при каких обстоятельствах это приводит к зомбиизму.Основная цель
join()
- убедиться, что дочерний процесс завершился до того, как основной процесс сделает что-либо, зависящее от работы дочернего процесса.Этимология
join()
заключается в том, что это противоположность томуfork
, что является общим термином в операционных системах семейства Unix для создания дочерних процессов. Один процесс «разветвляется» на несколько, а затем «объединяется» обратно в один.источник
join()
потому чтоjoin()
это то, что используется для ожиданияthreading.Thread
завершения объекта, аmultiprocessing
API предназначен дляthreading
максимально возможной имитации API.join()
необходим в случае, когда основному потоку нужны результаты работы подпотоков. Например, если вы визуализируете что-либо и назначаете 1/4 финального изображения каждому из 4 подпроцессов, и хотите отобразить все изображение, когда это будет сделано.Я не собираюсь подробно объяснять, что это
join
значит, но вот этимология и интуиция, лежащая в основе этого, которые должны помочь вам легче запомнить его значение.Идея состоит в том, что выполнение « разветвляется » на несколько процессов, один из которых является главным, а остальные - рабочими (или «подчиненными»). Когда рабочие закончили, они «присоединяются» к мастеру, чтобы можно было возобновить последовательное выполнение.
join
Метод вызывает главный процесс ждать работника , чтобы присоединиться к нему. Этот метод лучше было бы назвать «ожидание», так как это фактическое поведение, которое он вызывает в мастере (и это то, что он называется в POSIX, хотя потоки POSIX также называют это «соединением»). Соединение происходит только как эффект резьбы взаимодействующей должным образом, это не то , что мастер делает .Имена «вилка» и «объединение» используются в этом значении в многопроцессорной обработке с 1963 года .
источник
join
могло предшествовать его использованию в отношении конкатенации, а не наоборот.join()
используется для ожидания завершения рабочих процессов. Надо позвонитьclose()
илиterminate()
перед использованиемjoin()
.Как и @Russell, упомянутое соединение похоже на противоположность fork (которая порождает подпроцессы ).
Чтобы присоединиться к запуску, вы должны запустить его,
close()
что предотвратит отправку каких-либо других задач в пул и выйдет после завершения всех задач. В качестве альтернативы выполнениеterminate()
будет просто завершено путем немедленной остановки всех рабочих процессов."the child process will sit idle and not terminate, becoming a zombie you must manually kill"
это возможно, когда основной (родительский) процесс завершается, но дочерний процесс все еще выполняется и после завершения у него нет родительского процесса, которому можно было бы вернуть свой статус выхода.источник
В
join()
гарантирует вызов , что последующие строки кода не вызывается до завершения всех мультипроцессорных процессов.Например, без оператора
join()
следующий код будет вызыватьсяrestart_program()
еще до завершения процессов, что похоже на асинхронный и не является тем, что мы хотим (вы можете попробовать):источник
Чтобы дождаться, пока процесс завершит свою работу и выйдет, используйте метод join ().
и
Примечание. Важно, чтобы процесс join () был завершен после его завершения, чтобы дать фоновому механизму время обновить состояние объекта, чтобы отразить завершение.
Это хороший пример помог мне понять это: здесь
Одна вещь, которую я заметил лично, заключалась в том, что мой основной процесс был приостановлен до тех пор, пока ребенок не завершил свой процесс с помощью метода join (), который
multiprocessing.Process()
в первую очередь победил мою точку зрения .источник