Aprendendo sobre multiprocessamento Python (de um artigo PMOTW ) e adoraria alguns esclarecimentos sobre o que exatamente o join()
método está fazendo.
Em um antigo tutorial de 2008 afirma que sem a p.join()
chamada no código abaixo, "o processo filho ficará ocioso e não será encerrado, tornando-se um zumbi que você deve matar manualmente".
from multiprocessing import Process
def say_hello(name='world'):
print "Hello, %s" % name
p = Process(target=say_hello)
p.start()
p.join()
Eu adicionei uma impressão do PID
e também um time.sleep
para testar e, pelo que eu posso dizer, o processo termina sozinho:
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()
dentro de 20 segundos:
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
após 20 segundos:
947 ttys001 0:00.13 -bash
O comportamento é o mesmo com p.join()
adicionado de volta no final do arquivo. O Módulo Python da Semana oferece uma explicação muito legível do módulo ; "Para esperar até que um processo conclua seu trabalho e saia, use o método join ().", Mas parece que pelo menos o OS X estava fazendo isso de qualquer maneira.
Também estou me perguntando sobre o nome do método. O .join()
método está concatenando alguma coisa aqui? É concatenar um processo com seu fim? Ou ele apenas compartilha um nome com o .join()
método nativo do Python ?
fonte
CPU, Memory resources
estão sendo separados do processo pai e, em seguida,join
removidos novamente após a conclusão do processo filho?Respostas:
O
join()
método, quando usado comthreading
oumultiprocessing
, não está relacionado astr.join()
- não está realmente concatenando nada. Em vez disso, significa apenas "esperar que este [thread / processo] seja concluído". O nomejoin
é usado porque amultiprocessing
API do módulo deve ser semelhante àthreading
API dothreading
módulo e o módulo usajoin
para seuThread
objeto. Usando o termojoin
para significar "esperar a conclusão de um thread" é comum em muitas linguagens de programação, portanto, o Python também o adotou.Agora, o motivo pelo qual você vê o atraso de 20 segundos com e sem a chamada de
join()
é porque, por padrão, quando o processo principal está pronto para sair, ele implicitamente chamarájoin()
todas asmultiprocessing.Process
instâncias em execução . Isso não está tão claramente declarado nosmultiprocessing
documentos como deveria, mas é mencionado na seção Diretrizes de programação :Você pode substituir esse comportamento definindo a
daemon
bandeira noProcess
queTrue
antes de se iniciar o processo:Se você fizer isso, o processo filho será encerrado assim que o processo principal for concluído :
fonte
p.daemon=True
era para "iniciar um processo em segundo plano que é executado sem bloquear a saída do programa principal". Mas se "O processo daemon é encerrado automaticamente antes que o programa principal seja encerrado", qual é exatamente o seu uso?daemonic
processo filho não é muito seguro, porque o processo será encerrado sem permitir a limpeza de quaisquer recursos abertos que possa ter .. (cont.).multiprocessing
API foi projetada para imitar athreading
API o mais próximo possível. Osthreading.Thread
objetos demoníacos são encerrados assim que o thread principal termina, portanto, osmultiprocesing.Process
objetos demoníacos se comportam da mesma maneira.Sem o
join()
, o processo principal pode ser concluído antes do processo filho. Não tenho certeza sob quais circunstâncias isso leva ao zumbi.O objetivo principal de
join()
é garantir que um processo filho seja concluído antes que o processo principal faça qualquer coisa que dependa do trabalho do processo filho.A etimologia de
join()
é que é o oposto defork
, que é o termo comum nos sistemas operacionais da família Unix para criar processos filhos. Um único processo se "bifurca" em vários e depois "se junta" novamente em um.fonte
join()
porquejoin()
é o que é usado para esperarthreading.Thread
a conclusão de um objeto, e amultiprocessing
API foi criada para imitar athreading
API tanto quanto possível.join()
é necessário no caso em que a thread principal precisa dos resultados do trabalho das sub-threads. Por exemplo, se você estiver renderizando algo e atribuir 1/4 da imagem final a cada um dos 4 subprocessos, e quiser exibir a imagem inteira quando terminar.Não vou explicar em detalhes o que
join
significa, mas aqui está a etimologia e a intuição por trás disso, que deve ajudá-lo a se lembrar de seu significado com mais facilidade.A ideia é que a execução se " bifurque " em vários processos, dos quais um é o mestre e os demais são trabalhadores (ou "escravos"). Quando os trabalhadores terminam, eles "unem" o mestre para que a execução em série possa ser retomada.
O
join
método faz com que o processo mestre espere que um trabalhador se junte a ele. O método poderia ter sido chamado melhor de "espera", já que esse é o comportamento real que ele causa no mestre (e é isso que é chamado no POSIX, embora os threads do POSIX o chamem de "junção" também). A junção ocorre apenas como um efeito dos threads cooperando adequadamente, não é algo que o mestre faz .Os nomes "fork" e "join" têm sido usados com este significado no multiprocessamento desde 1963 .
fonte
join
pode ter precedido seu uso para se referir à concatenação, ao contrário do contrário.join()
é usado para aguardar a saída dos processos de trabalho. É preciso ligarclose()
outerminate()
antes de usarjoin()
.Como @Russell, a junção mencionada é como o oposto de fork (que gera subprocessos).
Para que o join seja executado, você deve executar o
close()
que impedirá que mais tarefas sejam enviadas ao pool e sairá assim que todas as tarefas forem concluídas. Como alternativa, a execuçãoterminate()
apenas será encerrada interrompendo todos os processos de trabalho imediatamente."the child process will sit idle and not terminate, becoming a zombie you must manually kill"
isso é possível quando o processo principal (pai) sai, mas o processo filho ainda está em execução e, uma vez concluído, não tem nenhum processo pai para o qual retornar seu status de saída.fonte
o
join()
chamada garante que as linhas subsequentes do seu código não sejam chamadas antes que todos os processos de multiprocessamento sejam concluídos.Por exemplo, sem o
join()
, o código a seguir será chamadorestart_program()
antes mesmo de os processos terminarem, o que é semelhante ao assíncrono e não é o que queremos (você pode tentar):fonte
Para esperar até que um processo conclua seu trabalho e saia, use o método join ().
e
Nota É importante juntar () o processo depois de encerrá-lo para dar tempo ao mecanismo de segundo plano para atualizar o status do objeto para refletir o encerramento.
Este é um bom exemplo que me ajudou a entender: aqui
Uma coisa que notei pessoalmente foi meu processo principal pausado até que a criança terminasse seu processo usando o método join (), o que frustrou o meu objetivo
multiprocessing.Process()
em primeiro lugar.fonte