Creando y reutilizando objetos en procesos python.

Tengo un problema paralelizantemente embarazoso que consiste en un montón de tareas que se resuelven de forma independiente. Resolver cada una de las tareas es bastante largo, por lo que este es un candidato principal para el multiprocesamiento.

El problema es que resolver mis tareas requiere crear un objeto específico que requiera mucho tiempo por sí solo pero que pueda reutilizarse para todas las tareas (piense en un progtwig binario externo que deba iniciarse), por lo que en la versión en serie hago algo Me gusta esto:

def costly_function(task, my_object): solution = solve_task_using_my_object return solution def solve_problem(): my_object = create_costly_object() tasks = get_list_of_tasks() all_solutions = [costly_function(task, my_object) for task in tasks] return all_solutions 

Cuando trato de paralelizar este progtwig utilizando multiprocesamiento, my_object no se puede pasar como parámetro por varios motivos (no se puede decapar y no debe ejecutar más de una tarea al mismo tiempo), por lo que tengo que recurrir para crear una instancia separada del objeto para cada tarea:

 def costly_function(task): my_object = create_costly_object() solution = solve_task_using_my_object return solution def psolve_problem(): pool = multiprocessing.Pool() tasks = get_list_of_tasks() all_solutions = pool.map_async(costly_function, tasks) return all_solutions.get() 

pero los costos adicionales de crear múltiples instancias de my_object hacen que este código sea solo un poco más rápido que el serializado.

Si pudiera crear una instancia separada de my_object en cada proceso y luego reutilizarlos para todas las tareas que se ejecuten en ese proceso, mis tiempos mejorarían significativamente. ¿Algún consejo sobre cómo hacer eso?

Encontré una forma sencilla de resolver mi propio problema sin traer ninguna herramienta además de la biblioteca estándar. Pensé que lo escribiría aquí en caso de que alguien más tuviera un problema similar.

multiprocessing.Pool acepta una función de initializer (con argumentos) que se ejecuta cuando se inicia cada proceso. El valor de retorno de esta función no se almacena en ninguna parte, pero se puede aprovechar la función para configurar una variable global:

 def init_process(): global my_object my_object = create_costly_object() def costly_function(task): global my_object solution = solve_task_using_my_object return solution def psolve_problem(): pool = multiprocessing.Pool(initializer=init_process) tasks = get_list_of_tasks() all_solutions = pool.map_async(costly_function, tasks) return all_solutions.get() 

Dado que cada proceso tiene un espacio de nombres global separado, los objetos instanciados no entran en conflicto, y se crean solo una vez por proceso.

Probablemente no sea la solución más elegante, pero es lo suficientemente simple y me da una aceleración casi lineal.

puede hacer que apio Project maneje todo esto por usted, entre otras muchas características, también tiene una manera de ejecutar algunas tareas de inicialización que pueden ser utilizadas por todas las tareas.

Tiene razón en estar limitado a los objetos que se pueden seleccionar cuando se utiliza el multiprocessing . ¿Estás absolutamente seguro de que tu objeto no se puede recoger?

¿Has probado el dill ? Si lo importa, en cualquier momento que se llame pickle, utilizará los enlaces de eneldo. Funcionó para mí, cuando intentaba utilizar el multiprocesamiento en ecuaciones sympy .