He creado una clase con varios métodos. Uno de los métodos consume mucho tiempo, my_process , y me gustaría hacer ese método en paralelo. Me encontré con Python Multiprocesamiento: aplique el método de clase a una lista de objetos, pero no estoy seguro de cómo aplicarlo a mi problema y qué efecto tendrá en los otros métodos de mi clase.
class MyClass(): def __init__(self, input): self.input = input self.result = int def my_process(self, multiply_by, add_to): self.result = self.input * multiply_by self._my_sub_process(add_to) return self.result def _my_sub_process(self, add_to): self.result += add_to list_of_numbers = range(0, 5) list_of_objects = [MyClass(i) for i in list_of_numbers] list_of_results = [obj.my_process(100, 1) for obj in list_of_objects] # multi-process this for-loop print list_of_numbers print list_of_results [0, 1, 2, 3, 4] [1, 101, 201, 301, 401]Voy a ir contra la corriente aquí, y sugiero ceñirme a lo más simple que pueda funcionar ;-) Es decir, las funciones tipo Pool.map() son ideales para esto, pero están restringidas a pasar un solo argumento. En lugar de hacer esfuerzos heroicos para evitar eso, simplemente escriba una función auxiliar que solo necesite un único argumento: una tupla. Entonces todo es fácil y claro.
Aquí hay un programa completo que adopta ese enfoque, que imprime lo que desea en Python 2 e independientemente del sistema operativo:
class MyClass(): def __init__(self, input): self.input = input self.result = int def my_process(self, multiply_by, add_to): self.result = self.input * multiply_by self._my_sub_process(add_to) return self.result def _my_sub_process(self, add_to): self.result += add_to import multiprocessing as mp NUM_CORE = 4 # set to the number of cores you want to use def worker(arg): obj, m, a = arg return obj.my_process(m, a) if __name__ == "__main__": list_of_numbers = range(0, 5) list_of_objects = [MyClass(i) for i in list_of_numbers] pool = mp.Pool(NUM_CORE) list_of_results = pool.map(worker, ((obj, 100, 1) for obj in list_of_objects)) pool.close() pool.join() print list_of_numbers print list_of_results Debo señalar que hay muchas ventajas al adoptar el enfoque muy simple que sugiero. Más allá de eso, "simplemente funciona" en Pythons 2 y 3, no requiere cambios en sus clases y es fácil de entender, también funciona bien con todos los métodos de Pool .
Sin embargo, si tiene varios métodos que desea ejecutar en paralelo, puede ser un poco molesto escribir una pequeña función de trabajo para cada uno. Así que aquí hay un poco de "magia" para solucionar eso. Cambiar worker() así:
def worker(arg): obj, methname = arg[:2] return getattr(obj, methname)(*arg[2:])Ahora, una sola función de trabajador es suficiente para cualquier cantidad de métodos, con cualquier cantidad de argumentos. En su caso específico, simplemente cambie una línea para que coincida:
list_of_results = pool.map(worker, ((obj, "my_process", 100, 1) for obj in list_of_objects))Las generalizaciones más o menos obvias también pueden servir para métodos con argumentos de palabras clave. Pero, en la vida real, normalmente me atengo a la sugerencia original. En algún momento, satisfacer las generalizaciones hace más daño que bien. Por otra parte, me gustan las cosas obvias ;-)
Si su clase no es "enorme", creo que la orientación al proceso es mejor. Se sugiere pool en multiprocesamiento.
Este es el tutorial -> https://docs.python.org/2/library/multiprocessing.html#using-a-pool-of-workers
Luego add_to de my_process ya que son rápidos y puede esperar hasta el final del último proceso.
def my_process(input, multiby): return xxxx def add_to(result,a_list): xxx p = Pool(5) res = [] for i in range(10): res.append(p.apply_async(my_process, (i,5))) p.join() # wait for the end of the last process for i in range(10): print res[i].get()Por lo general, la forma más fácil de ejecutar el mismo cálculo en paralelo es el método de map de un multiprocessing.Pool (o la función as_completed de concurrent.futures en Python 3).
Sin embargo, el método map aplica una función que solo toma un argumento para una iteración de datos usando múltiples procesos.
Entonces esta función no puede ser un método normal, porque requiere al menos dos argumentos; ¡también debe incluirse a self ! Sin embargo, podría ser un método estático. Consulte también esta respuesta para obtener una explicación más detallada.