Lamento no poder reproducir el error con un ejemplo más simple, y mi código es demasiado complicado para publicar. Si ejecuto el programa en el shell de IPython en lugar del Python normal, las cosas funcionan bien.
Busqué algunas notas anteriores sobre este problema. Todos fueron causados por el uso de grupo para llamar a la función definida dentro de una función de clase. Pero este no es el caso para mí.
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
Apreciaría cualquier ayuda.
Actualización : la función I pickle se define en el nivel superior del módulo. Aunque llama a una función que contiene una función anidada. es decir, f()
llama a g()
llamadas h()
que tienen una función anidada i()
, y estoy llamando pool.apply_async(f)
. f()
, g()
, h()
Están todos definidos en el nivel superior. Intenté un ejemplo más simple con este patrón y funciona.
dill
ypathos
. Sin embargo, no tuve suerte con ninguna de las soluciones cuando trabajo con vtkobjects :( ¿Alguien ha logrado ejecutar código python en procesamiento paralelo vtkPolyData?Respuestas:
Aquí hay una lista de lo que se puede encurtir . En particular, las funciones solo son seleccionables si se definen en el nivel superior de un módulo.
Esta pieza de código:
produce un error casi idéntico al publicado:
El problema es que
pool
todos los métodos usan amp.SimpleQueue
para pasar tareas a los procesos de trabajo. Todo lo que pasa por elmp.SimpleQueue
debe ser seleccionable yfoo.work
no es seleccionable ya que no está definido en el nivel superior del módulo.Se puede solucionar definiendo una función en el nivel superior, que llama
foo.work()
:Tenga en cuenta que
foo
es seleccionable, ya queFoo
se define en el nivel superior yfoo.__dict__
es seleccionable.fuente
pool = Pool()
línea aquí ). No esperaba eso, y esta podría ser la razón por la cual el problema de OP persistió.functool.partial
a una función de nivel superior también se puede seleccionar, incluso si se define dentro de otra función.Yo usaría
pathos.multiprocesssing
, en lugar demultiprocessing
.pathos.multiprocessing
Es una bifurcación demultiprocessing
que utilizadill
.dill
puede serializar casi cualquier cosa en python, por lo que puede enviar mucho más en paralelo. Lapathos
bifurcación también tiene la capacidad de trabajar directamente con múltiples funciones de argumento, como lo necesita para los métodos de clase.Obtenga
pathos
(y si lo deseadill
) aquí: https://github.com/uqfoundationfuente
sudo pip install git+https://github.com/uqfoundation/dill.git@master
ysudo pip install git+https://github.com/uqfoundation/pathos.git@master
sudo
(especialmente de fuentes externas como github). En cambio, recomendaría ejecutar:pip install --user git+...
pip install pathos
no funciona tristemente y da este mensaje:Could not find a version that satisfies the requirement pp==1.5.7-pathos (from pathos)
pip install pathos
ahora funciona ypathos
es compatible con python 3.multiprocess
es una bifurcación demultiprocessing
donde sedill
ha reemplazadopickle
en varios lugares en el código ... pero esencialmente, eso es todo.pathos
proporciona algunas capas API adicionalesmultiprocess
y también tiene backends adicionales. Pero, eso es lo esencial.Como han dicho otros,
multiprocessing
solo se pueden transferir objetos de Python a procesos de trabajo que se pueden encurtir. Si no puede reorganizar su código como lo describe unutbu, puede usardill
las capacidades extendidas de decapado / desempaquetado para transferir datos (especialmente datos de código) como se muestra a continuación.Esta solución requiere solo la instalación de
dill
y no otras bibliotecas comopathos
:fuente
dill
ypathos
... y si bien tienes razón, ¿no es mucho más agradable, más limpio y más flexible de usarpathos
que en mi respuesta? O tal vez soy un poco parcial ...pathos
en el momento de escribir y quería presentar una solución que esté muy cerca de la respuesta. Ahora que he visto su solución, estoy de acuerdo en que este es el camino a seguir.Doh… I didn't even think of doing it like that.
así que fue genial.for
bucle explícito . Normalmente vería que la rutina paralela toma una lista y devuelve una lista sin bucle.He descubierto que también puedo generar exactamente esa salida de error en un fragmento de código que funciona perfectamente al intentar usar el generador de perfiles en él.
Tenga en cuenta que esto fue en Windows (donde la bifurcación es un poco menos elegante).
Yo estaba corriendo:
Y descubrió que al eliminar el perfil se eliminó el error y al colocar el perfil se restableció. También me estaba volviendo loco porque sabía que el código solía funcionar. Estaba comprobando si algo había actualizado pool.py ... luego tuve una sensación de hundimiento y eliminé el perfil y eso fue todo.
Publicar aquí para los archivos en caso de que alguien más se encuentre con él.
fuente
pass
no era 'pickle'.Cuando surge este problema,
multiprocessing
una solución simple es cambiar dePool
aThreadPool
. Esto se puede hacer sin cambiar el código que no sea la importaciónEsto funciona porque ThreadPool comparte memoria con el hilo principal, en lugar de crear un nuevo proceso, esto significa que no es necesario el decapado.
La desventaja de este método es que Python no es el mejor lenguaje para el manejo de subprocesos: utiliza algo llamado Bloqueo global del intérprete para mantenerse seguro, lo que puede ralentizar algunos casos de uso aquí. Sin embargo, si está interactuando principalmente con otros sistemas (ejecutando comandos HTTP, hablando con una base de datos, escribiendo en sistemas de archivos), es probable que su código no esté vinculado por la CPU y no reciba mucho impacto. De hecho, cuando escribí puntos de referencia HTTP / HTTPS, descubrí que el modelo de subprocesos utilizado aquí tiene menos sobrecarga y demoras, ya que la sobrecarga de crear nuevos procesos es mucho mayor que la sobrecarga para crear nuevos subprocesos.
Entonces, si está procesando un montón de cosas en el espacio de usuario de Python, este podría no ser el mejor método.
fuente
También funciona para matrices numpy.
fuente
Este error también se producirá si tiene alguna función incorporada dentro del objeto modelo que se pasó al trabajo asíncrono.
Así que asegúrese de verificar que los objetos del modelo que se pasan no tienen funciones incorporadas. (En nuestro caso, estábamos usando la
FieldTracker()
función de django-model-utils dentro del modelo para rastrear cierto campo). Aquí está el enlace a la cuestión relevante de GitHub.fuente
Basándose en la solución @rocksportrocker, tendría sentido hacer eneldo al enviar y RECUPERAR los resultados.
fuente