No código de exemplo abaixo, gostaria de recuperar o valor de retorno da função worker
. Como posso fazer isso? Onde esse valor é armazenado?
Código de exemplo:
import multiprocessing
def worker(procnum):
'''worker function'''
print str(procnum) + ' represent!'
return procnum
if __name__ == '__main__':
jobs = []
for i in range(5):
p = multiprocessing.Process(target=worker, args=(i,))
jobs.append(p)
p.start()
for proc in jobs:
proc.join()
print jobs
Resultado:
0 represent!
1 represent!
2 represent!
3 represent!
4 represent!
[<Process(Process-1, stopped)>, <Process(Process-2, stopped)>, <Process(Process-3, stopped)>, <Process(Process-4, stopped)>, <Process(Process-5, stopped)>]
Não consigo encontrar o atributo relevante nos objetos armazenados jobs
.
multiprocessing.Queue
, em vez de umManager
aqui. Usar umManager
requer gerar um processo totalmente novo, que é um exagero quando umQueue
faria.multiprocessing.Pool.map
para processar sua lista de itens de trabalho.args=(my_function_argument, )
. Observe a,
vírgula aqui! Ou então o Python irá reclamar de "falta de argumentos posicionais". Levei 10 minutos para descobrir. Verifique também o uso manual (na seção "classe de processo").Acho que a abordagem sugerida por @sega_sai é a melhor. Mas ele realmente precisa de um exemplo de código, então aqui vai:
O que imprimirá os valores de retorno:
Se você estiver familiarizado com
map
(o Python 2 embutido), isso não deve ser muito desafiador. Caso contrário, dê uma olhada no link de sega_Sai .Observe como é necessário pouco código. (Observe também como os processos são reutilizados).
fonte
getpid()
retorno tem o mesmo valor? Estou executando o Python3pool.map
um intervalo de 1.000.000 usando mais de 10 processos, vejo no máximo dois pids diferentes.pool.apply_async
: docs.python.org/3/library/...Este exemplo mostra como usar uma lista de instâncias de multiprocessamento.Pipe para retornar seqüências de caracteres de um número arbitrário de processos:
Resultado:
Esta solução utiliza menos recursos que um multiprocessamento.Queue que usa
ou um multiprocessing.SimpleQueue que usa
É muito instrutivo procurar a fonte para cada um desses tipos.
fonte
Pipe
por processo versus umaQueue
para todos os processos. Não sei se isso acaba sendo mais eficiente em todos os casos.Por alguma razão, não consegui encontrar um exemplo geral de como fazer isso em
Queue
qualquer lugar (mesmo os exemplos de documentos do Python não geram vários processos), então aqui está o que eu comecei a trabalhar depois de 10 tentativas:Queue
é uma fila de bloqueio de segurança de thread que você pode usar para armazenar os valores de retorno dos processos filhos. Então você tem que passar a fila para cada processo. Algo menos óbvio aqui é que você tem queget()
partir da fila antes dejoin
osProcess
es ou então a fila enche e bloqueia tudo.Atualização para aqueles que são orientados a objetos (testados no Python 3.4):
fonte
Para qualquer pessoa que esteja procurando como obter um valor
Process
usandoQueue
:fonte
Queue
da minha função, deixe-me passar ojoin()
queue.put(ret)
antes de ligarp.start()
? Nesse caso, o segmento de trabalho será interrompido paraqueue.get()
sempre. Você pode replicar isso copiando meu snippet acima enquanto comentaqueue.put(ret)
.queue.get()
tem que acontecer antes dop.join()
. Agora funciona para mim.Parece que você deve usar a classe multiprocessing.Pool e usar os métodos .apply () .apply_async (), map ()
http://docs.python.org/library/multiprocessing.html?highlight=pool#multiprocessing.pool.AsyncResult
fonte
Você pode usar o
exit
built-in para definir o código de saída de um processo. Pode ser obtido a partir doexitcode
atributo do processo:Resultado:
fonte
O pacote pebble possui uma ótima alavancagem de abstração, o
multiprocessing.Pipe
que torna isso bastante simples:Exemplo de: https://pythonhosted.org/Pebble/#concurrent-decorators
fonte
Pensei em simplificar os exemplos mais simples copiados de cima, trabalhando para mim no Py3.6. O mais simples é
multiprocessing.Pool
:Você pode definir o número de processos no pool com, por exemplo
Pool(processes=5)
,. No entanto, o padrão é a contagem de CPU, portanto, deixe em branco para tarefas associadas à CPU. (As tarefas vinculadas à E / S geralmente se adequam aos threads de qualquer maneira, pois os threads estão aguardando a maior parte do tempo para compartilhar um núcleo da CPU.)Pool
Também se aplica à otimização de chunking .(Observe que o método worker não pode ser aninhado em um método. Inicialmente, defini meu método worker dentro do método que faz a chamada
pool.map
para manter tudo independente, mas os processos não puderam importá-lo e joguei "AttributeError : Não é possível selecionar o objeto local outer_method..inner_method ". Mais aqui . Ele pode estar dentro de uma classe.)(Aprecie a pergunta original especificada e
'represent!'
não a impressãotime.sleep()
, mas sem ela achei que algum código estava sendo executado simultaneamente quando não estava.)O Py3
ProcessPoolExecutor
também possui duas linhas (.map
retorna um gerador, portanto você precisa dolist()
):Com
Process
es simples :Use
SimpleQueue
se tudo que você precisa éput
eget
. O primeiro loop inicia todos os processos, antes que o segundo faça asqueue.get
chamadas de bloqueio . Acho que também não há motivo para ligarp.join()
.fonte
Uma solução simples:
Resultado:
fonte
Se você estiver usando o Python 3, poderá usar
concurrent.futures.ProcessPoolExecutor
como uma abstração conveniente:Resultado:
fonte
Modifiquei a resposta da vartec um pouco, pois precisava obter os códigos de erro da função. (Obrigado vertec !!! é um truque incrível)
Isso também pode ser feito com um,
manager.list
mas acho melhor colocá-lo em um ditado e armazenar uma lista nele. Dessa forma, mantemos a função e os resultados, pois não podemos ter certeza da ordem em que a lista será preenchida.fonte