PicklingError de multiprocesamiento de Python: no se puede seleccionar <tipo 'función'>
Lamento no poder reproducir el error con un ejemplo más simple y mi código es demasiado complicado para publicarlo. Si ejecuto el programa en el shell IPython en lugar del Python normal, las cosas funcionan bien.
Busqué algunas notas anteriores sobre este problema. Todos fueron causados por el uso de pool para llamar a una función definida dentro de una función de clase. Pero este no es mi 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
Apreciaría cualquier ayuda.
Actualización : La función que selecciono 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. Probé un ejemplo más simple con este patrón y, sin embargo, funciona.
Aquí tienes una lista de lo que se puede encurtir . En particular, las funciones solo se pueden seleccionar si están definidas en el nivel superior de un módulo.
Este fragmento de código:
import multiprocessing as mp
class Foo():
@staticmethod
def work(self):
pass
if __name__ == '__main__':
pool = mp.Pool()
foo = Foo()
pool.apply_async(foo.work)
pool.close()
pool.join()
arroja un error casi idéntico al que publicaste:
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 505, in run
self.__target(*self.__args, **self.__kwargs)
File "/usr/lib/python2.7/multiprocessing/pool.py", line 315, in _handle_tasks
put(task)
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed
El problema es que pool
todos los métodos utilizan a mp.SimpleQueue
para pasar tareas a los procesos de trabajo. Todo lo que pasa por mp.SimpleQueue
debe ser seleccionable y foo.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()
:
def work(foo):
foo.work()
pool.apply_async(work,args=(foo,))
Observe que foo
se puede seleccionar, ya que Foo
está definido en el nivel superior y foo.__dict__
se puede seleccionar.
Yo usaría pathos.multiprocesssing
, en lugar de multiprocessing
. pathos.multiprocessing
es un tenedor de multiprocessing
esos usos dill
. dill
Puede serializar casi cualquier cosa en Python, por lo que puede enviar mucho más en paralelo. La pathos
bifurcación también tiene la capacidad de trabajar directamente con funciones de múltiples argumentos, como es necesario para los métodos de clase.
>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> p = Pool(4)
>>> class Test(object):
... def plus(self, x, y):
... return x+y
...
>>> t = Test()
>>> p.map(t.plus, x, y)
[4, 6, 8, 10]
>>>
>>> class Foo(object):
... @staticmethod
... def work(self, x):
... return x+1
...
>>> f = Foo()
>>> p.apipe(f.work, f, 100)
<processing.pool.ApplyResult object at 0x10504f8d0>
>>> res = _
>>> res.get()
101
Obtenga pathos
(y si lo desea dill
) aquí:
https://github.com/uqfoundation