Seria possível criar um pool python que não seja demoníaco? Quero que um pool possa chamar uma função que tenha outro pool dentro.
Eu quero isso porque os processos deamon não podem criar processos. Especificamente, isso causará o erro:
AssertionError: daemonic processes are not allowed to have children
Por exemplo, considere o cenário em que function_a
há uma piscina que funciona function_b
e uma piscina que funciona function_c
. Esta cadeia de funções falhará porque function_b
está sendo executado em um processo daemon e os processos daemon não podem criar processos.
I want a pool to be able to call a function that has another pool inside
e como isso interfere no fato dos workers serem daemonizados.AssertionError: daemonic processes are not allowed to have children
Respostas:
A
multiprocessing.pool.Pool
classe cria os processos de trabalho em seu__init__
método, torna-os demoníacos e os inicia, e não é possível reconfigurar seusdaemon
atributos paraFalse
antes de serem iniciados (e depois disso não é mais permitido). Mas você pode criar sua própria subclasse demultiprocesing.pool.Pool
(multiprocessing.Pool
é apenas uma função de invólucro) e substituir sua própriamultiprocessing.Process
subclasse, que é sempre não demoníaca, para ser usada para os processos de trabalho.Aqui está um exemplo completo de como fazer isso. As partes importantes são as duas classes
NoDaemonProcess
eMyPool
no topo e para chamarpool.close()
epool.join()
em suaMyPool
instância no final.fonte
multiprocessing.freeze_support()
MyPool
vez do padrãoPool
? Em outras palavras, em troca da flexibilidade de iniciar processos filho, quais custos devo pagar? (Se não houvesse custos, presumivelmente o padrãoPool
teria usado processos não demoníacos).Pool
classe foi amplamente refatorada, entãoProcess
não é mais um atributo simples, mas um método, que retorna a instância do processo que obtém de um contexto . Tentei sobrescrever este método para retornar umaNoDaemonPool
instância, mas isso resultou na exceçãoAssertionError: daemonic processes are not allowed to have children
quando o Pool é usado.Tive a necessidade de empregar um pool não demoníaco no Python 3.7 e acabei adaptando o código postado na resposta aceita. Abaixo está o snippet que cria o pool não demoníaco:
Como a implementação atual de
multiprocessing
foi amplamente refatorada para ser baseada em contextos, precisamos fornecer umaNoDaemonContext
classe que tenha nossoNoDaemonProcess
atributo as.MyPool
irá então usar esse contexto em vez do padrão.Dito isso, devo alertar que há pelo menos 2 ressalvas para essa abordagem:
multiprocessing
pacote e, portanto, pode falhar a qualquer momento.multiprocessing
tornar tão difícil o uso de processos não demoníacos, muitos dos quais são explicados aqui . O mais atraente na minha opinião é:fonte
AttributeError: module 'multiprocessing' has no attribute 'pool'
no Python 3.8.0import multiprocessing.pool
O módulo de multiprocessamento tem uma interface agradável para usar pools com processos ou threads. Dependendo do seu caso de uso atual, você pode considerar o uso
multiprocessing.pool.ThreadPool
para seu Pool externo, o que resultará em threads (que permitem gerar processos de dentro) em vez de processos.Pode ser limitado pelo GIL, mas no meu caso particular (eu testei ambos) , o tempo de inicialização dos processos externos,
Pool
conforme criado aqui, superou em muito a solução comThreadPool
.É realmente fácil de trocar
Processes
paraThreads
. Leia mais sobre como usar umaThreadPool
solução aqui ou aqui .fonte
Em algumas versões do Python substituindo Piscina padrão para personalizado pode levantar erro:
AssertionError: group argument must be None for now
.Aqui encontrei uma solução que pode ajudar:
fonte
concurrent.futures.ProcessPoolExecutor
não tem essa limitação. Ele pode ter um pool de processos aninhados sem nenhum problema:O código de demonstração acima foi testado com Python 3.8.
Crédito: resposta por jfs
fonte
multiprocessing.Pool
dentro de umProcessPoolExecutor.Pool
também é possível!O problema que encontrei foi ao tentar importar globais entre módulos, fazendo com que a linha ProcessPool () fosse avaliada várias vezes.
globals.py
Em seguida, importe com segurança de outro lugar em seu código
fonte
Tenho visto pessoas lidando com esse problema usando
celery
o fork domultiprocessing
chamado billiard (extensões de pool de multiprocessamento), que permite que processos demoníacos gerem filhos. A solução é simplesmente substituir omultiprocessing
módulo por:fonte