Existem ferramentas no Python que são como o parfor do Matlab? Encontrei este tópico , mas tem quatro anos. Eu pensei que talvez alguém aqui possa ter uma experiência mais recente.
Aqui está um exemplo do tipo de coisa que eu gostaria de paralelizar:
X = np.random.normal(size=(10, 3))
F = np.zeros((10, ))
for i in range(10):
F[i] = my_function(X[i,:])
onde my_function
pega um ndarray
tamanho (1,3)
e retorna um escalar.
No mínimo, eu gostaria de usar vários núcleos simultaneamente - como o parfor. Em outras palavras, suponha um sistema de memória compartilhada com 8 a 16 núcleos.
python
parallel-computing
Paul G. Constantine
fonte
fonte
Respostas:
Joblib faz o que você deseja. O padrão de uso básico é:
onde
arg_instances
é a lista de valores para os quaismyfun
é calculado em paralelo. A principal restrição é quemyfun
deve ser uma função de nível superior. Obackend
parâmetro pode ser"threading"
ou"multiprocessing"
.Você pode passar parâmetros comuns adicionais para a função paralelizada. O corpo de
myfun
também pode se referir a variáveis globais inicializadas, os valores que estarão disponíveis para as crianças.Args e resultados podem ser praticamente qualquer coisa com o back-end de threading, mas os resultados precisam ser serializados com o back-end de multiprocessamento.
O Dask também oferece funcionalidade semelhante. Pode ser preferível se você estiver trabalhando com dados fora do núcleo ou tentando paralelizar cálculos mais complexos.
fonte
threading
back - end sofre com o gargalo do GIL e omultiprocessing
back - end gera uma grande sobrecarga devido à serialização de todos os parâmetros e valores de retorno. Veja esta resposta para obter detalhes de baixo nível do processamento paralelo no Python.map
que você pode usar diretamente. Além disso, se você usar o numk compilado mkl, ele paralelizará automaticamente as operações vetorizadas sem que você faça nada. O numpy em Ananconda é mkl ativado por padrão. Não existe uma solução universal. Joblib é muito barulhento e houve menos opções em 2015.O que você está procurando é o Numba , que pode paralelizar automaticamente um loop for. Da documentação deles
fonte
Sem assumir que algo especial na
my_function
escolhamultiprocessing.Pool().map()
é um bom palpite para paralelizar loops tão simples.joblib
,dask
,mpi
Cálculos ounumba
como proposto em outras respostas não parece trazer qualquer vantagem para tais casos de uso e adicionar dependências inúteis (para resumir eles são um exagero). É improvável que usar o encadeamento proposto em outra resposta seja uma boa solução, porque você precisa estar íntimo da interação GIL do seu código ou seu código deve fazer principalmente entrada / saída.Dito isso,
numba
pode ser uma boa idéia acelerar o código python puro seqüencial, mas acho que isso está fora do escopo da questão.No entanto, existem algumas ressalvas (mas que não devem afetar a maioria das aplicações):
if __name__ == "__main__"
my_function
não deve depender de estados compartilhados, como a comunicação com variáveis globais, porque os estados não são compartilhados entre processos. funções puras (funções nos sentidos matemáticos) são exemplos de funções que não compartilham estadosfonte
Minha impressão do parfor é que o MATLAB está encapsulando detalhes da implementação; portanto, ele pode estar usando paralelismo de memória compartilhada (que é o que você deseja) e paralelismo de memória distribuída (se você estiver executando um servidor de computação distribuída MATLAB ).
Se você deseja paralelismo de memória compartilhada e está executando algum tipo de loop paralelo de tarefa, o pacote de biblioteca padrão de multiprocessamento é provavelmente o que você deseja, talvez com um bom front-end, como joblib , como mencionado na publicação de Doug. A biblioteca padrão não vai desaparecer e é mantida, por isso é de baixo risco.
Existem outras opções também, como o Parallel Python e os recursos paralelos do IPython . Um rápido vislumbre do Parallel Python me faz pensar que está mais próximo do espírito do parfor, pois a biblioteca contém detalhes para o caso distribuído, mas o custo de fazer isso é que você deve adotar o ecossistema deles. O custo do uso do IPython é semelhante; você precisa adotar a maneira IPython de fazer as coisas, que podem ou não valer a pena para você.
Se você se preocupa com a memória distribuída, recomendo o mpi4py . Lisandro Dalcin faz um ótimo trabalho, e o mpi4py é usado nos wrappers PETSc Python, então eu não acho que isso vai desaparecer tão cedo. Assim como o multiprocessamento, é uma interface de baixo nível (er) para paralelismo do que o parfor, mas provavelmente durará um tempo.
fonte
Antes de procurar uma ferramenta "caixa preta", que pode ser usada para executar funções python "genéricas" paralelas, sugiro que analise como
my_function()
pode ser paralelizado manualmente.Primeiro, compare o tempo de execução
my_function(v)
com ofor
overhead do loop python : [C] Osfor
loops do Python são muito lentos, portanto o tempo gastomy_function()
pode ser insignificante.Segunda verificação, se houver uma implementação de vetor simples
my_function(v)
que não exija loops:F[:] = my_vector_function(X)
(Esses dois primeiros pontos são bastante triviais, perdoe-me se eu os mencionei aqui apenas por completude.)
O terceiro e mais importante ponto, pelo menos para as implementações de CPython, é verificar se
my_function
passa a maior parte do tempo dentro ou fora do bloqueio global de intérpretes , ou GIL . Se o tempo for gasto fora do GIL, othreading
módulo de biblioteca padrão deve ser usado. ( Aqui está um exemplo). BTW, pode-se pensar em escrevermy_function()
como uma extensão C apenas para liberar o GIL.Finalmente, se
my_function()
não liberar o GIL, pode-se usar omultiprocessing
módulo .Referências: documentos em Python sobre execução simultânea e introdução numpy / scipy no processamento paralelo .
fonte
Você pode tentar Julia. É bem parecido com o Python e possui muitas construções do MATLAB. A tradução aqui é:
Isso também torna os números aleatórios paralelamente e apenas concatena os resultados no final durante a redução. Isso usa multiprocessamento (então você precisa
addprocs(N)
adicionar processos antes de usar, e isso também funciona em vários nós em um HPC, como mostrado nesta postagem do blog ).Você também pode usar
pmap
:Se você quiser paralelismo de encadeamento, poderá usá-lo
Threads.@threads
(embora certifique-se de tornar o algoritmo seguro para encadeamento). Antes de abrir Julia, defina a variável de ambiente JULIA_NUM_THREADS, então é:Aqui, faço uma matriz separada para cada thread, para que não entrem em conflito ao serem adicionadas à matriz e concatenem as matrizes posteriormente. O encadeamento é bem novo, então agora existe apenas o uso direto de encadeamentos, mas tenho certeza de que reduções e mapas de encadeamentos serão adicionados exatamente como no multiprocessamento.
fonte
eu recomendo usar as funções Paralela e atrasada da biblioteca joblib, use o módulo "tempfile" para criar memória compartilhada temporária para matrizes enormes. Os exemplos e o uso podem ser encontrados aqui https://pythonhosted.org/joblib/parallel.html
fonte