Je suis désolé de ne pas pouvoir reproduire l'erreur avec un exemple plus simple et mon code est trop compliqué à publier. Si j'exécute le programme dans le shell IPython au lieu du Python normal, les choses fonctionnent bien.
J'ai recherché quelques notes précédentes sur ce problème. Ils ont tous été causés par l'utilisation de pool pour appeler la fonction définie dans une fonction de classe. Mais ce n'est pas le cas pour moi.
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
J'apprécierais toute aide.
Mise à jour : La fonction I pickle est définie au niveau supérieur du module. Bien qu'il appelle une fonction qui contient une fonction imbriquée. c'est-à-dire, f()
appelle des g()
appels h()
qui ont une fonction imbriquée i()
, et j'appelle pool.apply_async(f)
. f()
, g()
, h()
Sont tous définis au niveau supérieur. J'ai essayé un exemple plus simple avec ce modèle et cela fonctionne cependant.
dill
etpathos
. Cependant, je n'ai aucune chance avec l'une des solutions lorsque je travaille avec vtkobjects :( N'importe qui a réussi à exécuter du code python en traitement parallèle vtkPolyData?Réponses:
Voici une liste de ce qui peut être mariné . En particulier, les fonctions ne sont picklables que si elles sont définies au niveau supérieur d'un module.
Ce morceau de code:
renvoie une erreur presque identique à celle que vous avez publiée:
Le problème est que
pool
toutes les méthodes utilisent amp.SimpleQueue
pour transmettre des tâches aux processus de travail. Tout ce qui passe par lemp.SimpleQueue
doit être pickable, etfoo.work
n'est pas picklable car il n'est pas défini au niveau supérieur du module.Il peut être corrigé en définissant une fonction au niveau supérieur, qui appelle
foo.work()
:Notez que
foo
c'est pickable, carFoo
est défini au niveau supérieur etfoo.__dict__
est picklable.la source
pool = Pool()
ligne ici ). Je ne m'attendais pas à cela, et cela pourrait être la raison pour laquelle le problème d'OP a persisté.functool.partial
à une fonction de niveau supérieur soit également picklable, même s'il est défini dans une autre fonction.J'utiliserais
pathos.multiprocesssing
, au lieu demultiprocessing
.pathos.multiprocessing
est une fourchette demultiprocessing
ces utilisationsdill
.dill
peut sérialiser presque n'importe quoi en python, vous pouvez donc en envoyer beaucoup plus en parallèle. Lepathos
fork a également la possibilité de travailler directement avec plusieurs fonctions d'argument, comme vous en avez besoin pour les méthodes de classe.Obtenez
pathos
(et si vous le souhaitezdill
) ici: https://github.com/uqfoundationla source
sudo pip install git+https://github.com/uqfoundation/dill.git@master
etsudo pip install git+https://github.com/uqfoundation/pathos.git@master
sudo
(à partir de sources externes telles que github en particulier). Au lieu de cela, je recommanderais d'exécuter:pip install --user git+...
pip install pathos
ne fonctionne tout simplement pas et donne ce message:Could not find a version that satisfies the requirement pp==1.5.7-pathos (from pathos)
pip install pathos
fonctionne maintenant etpathos
est compatible python 3.multiprocess
est une fourchette d'multiprocessing
oùdill
a remplacépickle
à plusieurs endroits dans le code ... mais essentiellement, c'est tout.pathos
fournit des couches API supplémentairesmultiprocess
et a également des backends supplémentaires. Mais, c'est l'essentiel.Comme d'autres l'ont dit,
multiprocessing
il ne peut transférer que des objets Python vers des processus de travail qui peuvent être décapés. Si vous ne pouvez pas réorganiser votre code comme décrit par unutbu, vous pouvez utiliserdill
les capacités étendues de pickling / unpickling pour transférer des données (en particulier des données de code) comme je le montre ci-dessous.Cette solution nécessite uniquement l'installation de
dill
et aucune autre bibliothèque commepathos
:la source
dill
etpathos
… et pendant que vous avez raison, n'est-il pas tellement plus agréable et plus propre et plus flexible à utiliser aussipathos
que dans ma réponse? Ou peut-être que je suis un peu biaisé…pathos
au moment de la rédaction de cet article et je voulais présenter une solution très proche de la réponse. Maintenant que j'ai vu votre solution, je conviens que c'est la voie à suivre.Doh… I didn't even think of doing it like that.
dit: c'était plutôt cool.for
boucle explicite . Je verrais normalement une routine parallèle prendre une liste et retourner une liste sans boucle.J'ai trouvé que je peux également générer exactement cette sortie d'erreur sur un morceau de code fonctionnant parfaitement en essayant d'utiliser le profileur dessus.
Notez que c'était sur Windows (où la fourche est un peu moins élégante).
Je courais:
Et constaté que la suppression du profilage supprimait l'erreur et que le placement du profilage la restaurait. Me rendait fou aussi parce que je savais que le code fonctionnait. Je vérifiais si quelque chose avait mis à jour pool.py ... puis avait un sentiment de naufrage et éliminé le profilage et c'était tout.
Publier ici pour les archives au cas où quelqu'un d'autre les rencontrerait.
la source
pass
n'était pas «picklable».Lorsque ce problème survient,
multiprocessing
une solution simple consiste à passer dePool
àThreadPool
. Cela peut être fait sans changement de code autre que l’importationCela fonctionne parce que ThreadPool partage la mémoire avec le thread principal, plutôt que de créer un nouveau processus - cela signifie que le décapage n'est pas requis.
L'inconvénient de cette méthode est que python n'est pas le plus grand langage de gestion des threads - il utilise quelque chose appelé Global Interpreter Lock pour rester sûr, ce qui peut ralentir certains cas d'utilisation ici. Cependant, si vous interagissez principalement avec d'autres systèmes (exécution de commandes HTTP, conversation avec une base de données, écriture sur des systèmes de fichiers), votre code n'est probablement pas lié par le processeur et ne prendra pas beaucoup de succès. En fait, j'ai trouvé lors de l'écriture de benchmarks HTTP / HTTPS que le modèle fileté utilisé ici a moins de temps et de délais, car le temps de création de nouveaux processus est beaucoup plus élevé que le temps de création de nouveaux threads.
Donc, si vous traitez une tonne de choses dans l'espace utilisateur python, ce n'est peut-être pas la meilleure méthode.
la source
Il fonctionne également pour les tableaux numpy.
la source
Cette erreur se produira également si vous avez une fonction intégrée dans l'objet modèle qui a été transmise au travail asynchrone.
Assurez-vous donc de vérifier que les objets de modèle transmis n'ont pas de fonctions intégrées. (Dans notre cas, nous utilisions la
FieldTracker()
fonction de django-model-utils à l'intérieur du modèle pour suivre un certain champ). Voici le lien vers le problème GitHub pertinent.la source
S'appuyant sur la solution @rocksportrocker, il serait judicieux de l'analyser lors de l'envoi et de la récupération des résultats.
la source