PicklingError de multiprocesamiento de Python: no se puede seleccionar <tipo 'función'>

Resuelto CuriousMind asked hace 12 años • 10 respuestas

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.

CuriousMind avatar Jan 10 '12 21:01 CuriousMind
Aceptado

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 pooltodos los métodos utilizan a mp.SimpleQueuepara pasar tareas a los procesos de trabajo. Todo lo que pasa por mp.SimpleQueuedebe ser seleccionable y foo.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():

def work(foo):
    foo.work()

pool.apply_async(work,args=(foo,))

Observe que foose puede seleccionar, ya que Fooestá definido en el nivel superior y foo.__dict__se puede seleccionar.

unutbu avatar Jan 10 '2012 14:01 unutbu

Yo usaría pathos.multiprocesssing, en lugar de multiprocessing. pathos.multiprocessinges un tenedor de multiprocessingesos usos dill. dillPuede serializar casi cualquier cosa en Python, por lo que puede enviar mucho más en paralelo. La pathosbifurcació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

Mike McKerns avatar Jan 25 '2014 01:01 Mike McKerns