2012-04-14 7 views
7

(ejemplo enormemente simplificado) funciona bien (Python 2.6.6, Debian Squeeze):¿Patrones de uso alternativos para el multiprocesamiento de python que evitan la proliferación del estado global? Este

from multiprocessing import Pool 
import numpy as np 

src=None 

def process(row): 
    return np.sum(src[row]) 

def main(): 
    global src 
    src=np.ones((100,100)) 

    pool=Pool(processes=16) 
    rows=pool.map(process,range(100)) 
    print rows 

if __name__ == "__main__": 
    main() 

sin embargo, después de años de ser enseñado mal estado global !!!, todos mis instintos me dicen que realmente realmente bien estaría escribiendo algo más cercano a:

from multiprocessing import Pool 
import numpy as np 

def main(): 
    src=np.ones((100,100)) 

    def process(row): 
     return np.sum(src[row]) 

    pool=Pool(processes=16) 
    rows=pool.map(process,range(100)) 
    print rows 

if __name__ == "__main__": 
    main() 

pero por supuesto que no funciona (cuelga incapaces de conservar en vinagre algo).

El ejemplo aquí es trivial, pero cuando se agregan varias funciones de "proceso", y cada una de ellas depende de múltiples entradas adicionales ... bueno, todo se parece un poco a algo escrito en BASIC hace 30 años . Intentar utilizar clases para al menos agregar el estado con las funciones apropiadas parece una solución obvia, pero doesn't seem to be that easy en la práctica.

¿Hay algún patrón o estilo recomendado para usar multiprocesamiento.pool que evitará la proliferación del estado global para admitir cada función sobre la que quiero hacer un mapa paralelo?

¿Cómo se enfrentan los experimentados "profesionales de multiprocesamiento" con esto?

actualización: Tenga en cuenta que estoy realmente interesado en gran parte del procesamiento matrices más grandes, por lo que las variaciones en la por encima del cual pickle src cada llamada/iteración no son tan buenos como los que tenedor en los procesos de trabajo de dicho grupo.

+0

No soy un experimentado multiprocesamiento pro ni nada, pero déjeme preguntarle por qué no puedes simplemente haga pool.map (process, product ([src], range (100))) y cambie la función de proceso para aceptar ambas variables como args? ¿Esto es altamente ineficiente también? – luke14free

+0

@ luke14free: Sí, eso acabaría con la matriz src para cada llamada, y estoy realmente interesado en datos/matrices mucho más grandes que los del código de ejemplo anterior, por lo que no es ideal. Con el grupo de procesos, cualquier estado que se configure en el punto en que se crea el grupo se bifurca en los procesos de trabajo y está disponible para que ellos lean "de forma gratuita". La idea ayudaría a evitar poner más variables menores de "variables de control" (por ejemplo, banderas) en globales, gracias. – timday

Respuesta

5

Siempre se puede pasar un objeto se puede llamar así, entonces el objeto puede Containe el estado compartido:

from multiprocessing import Pool 
import numpy as np 

class RowProcessor(object): 
    def __init__(self, src): 
     self.__src = src 
    def __call__(self, row): 
     return np.sum(self.__src[row]) 

def main(): 
    src=np.ones((100,100)) 
    p = RowProcessor(src) 

    pool=Pool(processes=16) 
    rows = pool.map(p, range(100)) 
    print rows 

if __name__ == "__main__": 
    main() 
+0

Parece interesante ... probará este estilo e informará de nuevo ... – timday

+0

Yup funciona muy bien gracias; adios bye globals. Normalmente esperaría más tiempo antes de aceptar una solución para ver si aparece algo más, pero esto es perfecto. Probé clases para este problema antes y no tuve éxito; parece que llamable hace toda la diferencia. – timday

+2

¿No saldría el invocable y volverá al punto de partida? –

Cuestiones relacionadas