Lamento não poder reproduzir o erro com um exemplo mais simples, e meu código é muito complicado para postar. Se eu executar o programa no shell IPython em vez do Python comum, as coisas funcionam bem.
Procurei algumas notas anteriores sobre esse problema. Todos eles foram causados pelo uso de pool para chamar a função definida dentro de uma função de classe. Mas esse não é o meu caso.
Exception in thread Thread-3:
Traceback (most recent call last):
File "/usr/lib64/python2.7/threading.py", line 552, in __bootstrap_inner
self.run()
File "/usr/lib64/python2.7/threading.py", line 505, in run
self.__target(*self.__args, **self.__kwargs)
File "/usr/lib64/python2.7/multiprocessing/pool.py", line 313, in _handle_tasks
put(task)
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed
Eu apreciaria qualquer ajuda.
Atualização : A função que eu seleciono é definida no nível superior do módulo. Embora chame uma função que contenha uma função aninhada. ou seja, f()
chama as g()
chamadas h()
que têm uma função aninhada i()
, e eu estou chamando pool.apply_async(f)
. f()
, g()
, h()
São todos definidos no nível superior. Eu tentei exemplo mais simples com esse padrão e funciona embora.
dill
epathos
. No entanto, eu não tive sorte com qualquer uma das soluções quando se trabalha com vtkobjects :( Alguém conseguiu executar código python em processamento paralelo vtkPolyData?Respostas:
Aqui está uma lista do que pode ser conservado em conserva . Em particular, as funções só podem ser selecionadas se definidas no nível superior de um módulo.
Este trecho de código:
gera um erro quase idêntico ao que você postou:
O problema é que
pool
todos os métodos usam amp.SimpleQueue
para passar tarefas para os processos de trabalho. Tudo o que passa pelomp.SimpleQueue
deve ser selecionável efoo.work
não pode ser selecionado, pois não está definido no nível superior do módulo.Pode ser corrigido definindo uma função no nível superior, que chama
foo.work()
:Observe que
foo
é selecionável, uma vez queFoo
é definido no nível superior efoo.__dict__
é selecionável.fonte
pool = Pool()
linha aqui ). Eu não esperava isso, e essa pode ser a razão pela qual o problema do OP persistiu.functool.partial
a uma função de nível superior também pode ser ativado, mesmo que seja definido dentro de outra função.Eu usaria
pathos.multiprocesssing
, em vez demultiprocessing
.pathos.multiprocessing
é um garfomultiprocessing
que usadill
.dill
pode serializar quase tudo em python, para que você possa enviar muito mais em paralelo. Opathos
fork também tem a capacidade de trabalhar diretamente com várias funções de argumento, conforme necessário para métodos de classe.Obtenha
pathos
(e se quiserdill
) aqui: https://github.com/uqfoundationfonte
sudo pip install git+https://github.com/uqfoundation/dill.git@master
esudo pip install git+https://github.com/uqfoundation/pathos.git@master
sudo
(de fontes externas como o github especialmente). Em vez disso, eu recomendaria executar:pip install --user git+...
pip install pathos
não funciona tristemente e dá a seguinte mensagem:Could not find a version that satisfies the requirement pp==1.5.7-pathos (from pathos)
pip install pathos
agora funciona epathos
é compatível com python 3.multiprocess
é um fork demultiprocessing
ondedill
foi substituídopickle
em vários lugares no código ... mas essencialmente é isso.pathos
fornece algumas camadas de API adicionaismultiprocess
e também possui back-end adicionais. Mas, essa é a essência disso.Como outros já disseram,
multiprocessing
só é possível transferir objetos Python para processos de trabalho que podem ser decapados. Se você não conseguir reorganizar seu código conforme descrito por unutbu, poderá usar os recursosdill
estendidos de decapagem / remoção de pickp para transferir dados (especialmente dados de código), como mostramos abaixo.Esta solução requer apenas a instalação
dill
e nenhuma outra biblioteca comopathos
:fonte
dill
epathos
... e, quando você estiver certo, não é tão melhor e mais limpo e mais flexível usar tambémpathos
como na minha resposta? Ou talvez eu esteja um pouco tendenciosa ...pathos
no momento da redação e queria apresentar uma solução muito próxima da resposta. Agora que vi sua solução, concordo que este é o caminho a percorrer.Doh… I didn't even think of doing it like that.
então isso foi legal.for
loop explícito . Eu normalmente veria a rotina paralela pegar uma lista e retornar uma lista sem loop.Descobri que também posso gerar exatamente essa saída de erro em um pedaço de código que funciona perfeitamente, tentando usar o criador de perfil nele.
Observe que isso foi no Windows (onde o garfo é um pouco menos elegante).
Eu estava correndo:
E descobriu que a remoção da criação de perfil removeu o erro e a colocação do perfil o restaurou. Estava me deixando maluco também porque sabia que o código costumava funcionar. Eu estava verificando se algo havia atualizado pool.py ... então tive uma sensação de que estava afundando e eliminado a criação de perfil e foi isso.
Postando aqui para os arquivos, caso alguém o encontre.
fonte
pass
não era 'pickle'able.Quando esse problema surge,
multiprocessing
uma solução simples é alternar dePool
paraThreadPool
. Isso pode ser feito sem nenhuma alteração de código além da importaçãoIsso funciona porque o ThreadPool compartilha a memória com o thread principal, em vez de criar um novo processo - isso significa que a decapagem não é necessária.
A desvantagem desse método é que o python não é a melhor linguagem para lidar com threads - ele usa algo chamado Global Interpreter Lock para manter o thread seguro, o que pode retardar alguns casos de uso aqui. No entanto, se você estiver interagindo principalmente com outros sistemas (executando comandos HTTP, conversando com um banco de dados, gravando em sistemas de arquivos), seu código provavelmente não está vinculado à CPU e não será afetado. De fato, descobri ao escrever benchmarks HTTP / HTTPS que o modelo encadeado usado aqui tem menos sobrecarga e atrasos, pois a sobrecarga da criação de novos processos é muito maior que a sobrecarga da criação de novos encadeamentos.
Portanto, se você estiver processando uma tonelada de coisas no espaço do usuário python, talvez esse não seja o melhor método.
fonte
Também funciona para matrizes numpy.
fonte
Este erro também ocorrerá se você tiver alguma função embutida dentro do objeto de modelo que foi passado para o trabalho assíncrono.
Portanto, verifique se os objetos de modelo passados não possuem funções embutidas. (No nosso caso, estávamos usando a
FieldTracker()
função django-model-utils dentro do modelo para rastrear um determinado campo). Aqui está o link para a questão relevante do GitHub.fonte
Com base na solução @rocksportrocker, faria sentido dill ao enviar e RECVing os resultados.
fonte