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.

dillypathos. 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
pooltodos los métodos usan amp.SimpleQueuepara pasar tareas a los procesos de trabajo. Todo lo que pasa por elmp.SimpleQueuedebe ser seleccionable yfoo.workno 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
fooes seleccionable, ya queFoose 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.partiala 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.multiprocessingEs una bifurcación demultiprocessingque utilizadill.dillpuede serializar casi cualquier cosa en python, por lo que puede enviar mucho más en paralelo. Lapathosbifurcació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@masterysudo pip install git+https://github.com/uqfoundation/pathos.git@mastersudo(especialmente de fuentes externas como github). En cambio, recomendaría ejecutar:pip install --user git+...pip install pathosno funciona tristemente y da este mensaje:Could not find a version that satisfies the requirement pp==1.5.7-pathos (from pathos)pip install pathosahora funciona ypathoses compatible con python 3.multiprocesses una bifurcación demultiprocessingdonde sedillha reemplazadopickleen varios lugares en el código ... pero esencialmente, eso es todo.pathosproporciona algunas capas API adicionalesmultiprocessy también tiene backends adicionales. Pero, eso es lo esencial.Como han dicho otros,
multiprocessingsolo 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 usardilllas 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
dilly no otras bibliotecas comopathos:fuente
dillypathos... y si bien tienes razón, ¿no es mucho más agradable, más limpio y más flexible de usarpathosque en mi respuesta? O tal vez soy un poco parcial ...pathosen 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.forbucle 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
passno era 'pickle'.Cuando surge este problema,
multiprocessinguna solución simple es cambiar dePoolaThreadPool. 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