¿Los procesos secundarios generados a través del multiprocesamiento comparten objetos creados anteriormente en el programa?
Tengo la siguiente configuración:
do_some_processing(filename):
for line in file(filename):
if line.split(',')[0] in big_lookup_object:
# something here
if __name__ == '__main__':
big_lookup_object = marshal.load('file.bin')
pool = Pool(processes=4)
print pool.map(do_some_processing, glob.glob('*.data'))
Estoy cargando un gran objeto en la memoria, luego creo un grupo de trabajadores que necesitan hacer uso de ese gran objeto. Se accede al objeto grande de solo lectura, no necesito pasar modificaciones entre procesos.
Mi pregunta es: ¿el objeto grande está cargado en la memoria compartida, como lo estaría si generara un proceso en unix / c, o cada proceso carga su propia copia del objeto grande?
Actualización: para aclarar más: big_lookup_object es un objeto de búsqueda compartido. No necesito dividir eso y procesarlo por separado. Necesito guardar una sola copia. El trabajo que necesito dividir es leer muchos otros archivos grandes y buscar los elementos en esos archivos grandes con el objeto de búsqueda.
Actualización adicional: la base de datos es una buena solución, memcached podría ser una mejor solución y el archivo en disco (shelve o dbm) podría ser incluso mejor. En esta pregunta estaba particularmente interesado en una solución de memoria. Para la solución final, usaré hadoop, pero quería ver si también puedo tener una versión local en memoria.
fuente
marshal.load
a los padres y a cada hijo (cada proceso importa el módulo).Respuestas:
"¿Los procesos secundarios generados a través del multiprocesamiento comparten objetos creados anteriormente en el programa?"
No (python antes de 3.8) y Sí en 3.8 ( https://docs.python.org/3/library/multiprocessing.shared_memory.html#module-multiprocessing.shared_memory )
Los procesos tienen espacio de memoria independiente.
Solución 1
Para aprovechar al máximo una estructura grande con muchos trabajadores, haga esto.
Escriba cada trabajador como un "filtro": lee los resultados intermedios de stdin, funciona, escribe resultados intermedios en stdout.
Conecte a todos los trabajadores como una tubería:
Cada proceso lee, trabaja y escribe.
Esto es notablemente eficiente ya que todos los procesos se ejecutan al mismo tiempo. Las escrituras y lecturas pasan directamente a través de búferes compartidos entre los procesos.
Solucion 2
En algunos casos, tiene una estructura más compleja, a menudo una estructura "en abanico". En este caso, tiene un padre con varios hijos.
El padre abre los datos de origen. El padre bifurca a varios hijos.
El padre lee la fuente, distribuye partes de la fuente a cada hijo que se ejecuta simultáneamente.
Cuando el padre llegue al final, cierre la tubería. El niño termina el archivo y termina normalmente.
Las partes secundarias son agradables de escribir porque cada niño simplemente lee
sys.stdin
.El padre tiene un poco de juego de pies elegante para engendrar a todos los hijos y retener las tuberías correctamente, pero no es tan malo.
Fan-in es la estructura opuesta. Varios procesos que se ejecutan de forma independiente deben intercalar sus entradas en un proceso común. El recopilador no es tan fácil de escribir, ya que tiene que leer de muchas fuentes.
La lectura de muchas canalizaciones con nombre a menudo se realiza utilizando el
select
módulo para ver qué canalizaciones tienen entradas pendientes.Solución 3
La búsqueda compartida es la definición de una base de datos.
Solución 3A: cargue una base de datos. Deje que los trabajadores procesen los datos en la base de datos.
Solución 3B: cree un servidor muy simple usando werkzeug (o similar) para proporcionar aplicaciones WSGI que respondan a HTTP GET para que los trabajadores puedan consultar el servidor.
Solución 4
Objeto de sistema de archivos compartido. Unix OS ofrece objetos de memoria compartida. Estos son solo archivos que se asignan a la memoria para que se realice el intercambio de E / S en lugar de más lecturas almacenadas en búfer por convención.
Puede hacer esto desde un contexto de Python de varias maneras
Escriba un programa de inicio que (1) rompa su objeto gigantesco original en objetos más pequeños y (2) inicie trabajadores, cada uno con un objeto más pequeño. Los objetos más pequeños podrían ser objetos de Python encurtidos para ahorrar un poco de tiempo de lectura de archivos.
Escriba un programa de inicio que (1) lea su objeto gigantesco original y escriba un archivo codificado por bytes con estructura de página utilizando
seek
operaciones para garantizar que las secciones individuales sean fáciles de encontrar con búsquedas simples. Esto es lo que hace un motor de base de datos: dividir los datos en páginas, hacer que cada página sea fácil de localizar mediante un archivoseek
.Genere trabajadores con acceso a este archivo de gran tamaño con estructura de página. Cada trabajador puede buscar las partes relevantes y hacer su trabajo allí.
fuente
¿Los procesos secundarios generados a través del multiprocesamiento comparten objetos creados anteriormente en el programa?
Depende. Para las variables globales de solo lectura, a menudo se puede considerar así (aparte de la memoria consumida); de lo contrario, no debería.
La documentación del multiprocesamiento dice:
Better to inherit than pickle/unpickle
Explicitly pass resources to child processes
Global variables
Ejemplo
En Windows (CPU única):
Con
sleep
:Sin
sleep
:fuente
z
no se comparte. Por tanto, esto responde a la pregunta con: "no, al menos en Windows, una variable padre no se comparte entre los hijos".z
caso), se pueden considerar compartidos.S. Lot tiene razón. Los atajos de multiprocesamiento de Python le brindan efectivamente una porción de memoria separada y duplicada.
En la mayoría de los sistemas * nix, usar una llamada de nivel inferior a le
os.fork()
dará, de hecho, memoria de copia sobre escritura, que podría ser lo que está pensando. AFAIK, en teoría, en el programa más simplista posible, podría leer esos datos sin tenerlos duplicados.Sin embargo, las cosas no son tan simples en el intérprete de Python. Los datos del objeto y los metadatos se almacenan en el mismo segmento de memoria, por lo que incluso si el objeto nunca cambia, algo como un contador de referencia para ese objeto que se incrementa provocará una escritura en la memoria y, por lo tanto, una copia. Casi cualquier programa de Python que esté haciendo más que "imprimir 'hola'" provocará incrementos en el recuento de referencias, por lo que es probable que nunca se dé cuenta del beneficio de copiar sobre escritura.
Incluso si alguien lograra piratear una solución de memoria compartida en Python, intentar coordinar la recolección de basura en los procesos probablemente sería bastante doloroso.
fuente
Si está ejecutando en Unix, es posible que compartan el mismo objeto, debido a cómo funciona la bifurcación (es decir, los procesos secundarios tienen una memoria separada pero es de copia en escritura, por lo que puede compartirse siempre que nadie la modifique). Intenté lo siguiente:
y obtuvo la siguiente salida:
Por supuesto, esto no prueba que no se haya realizado una copia, pero debería poder verificar eso en su situación mirando la salida de
ps
para ver cuánta memoria real está usando cada subproceso.fuente
Los diferentes procesos tienen diferentes espacios de direcciones. Como ejecutar diferentes instancias del intérprete. Para eso es IPC (comunicación entre procesos).
Puede utilizar colas o canalizaciones para este propósito. También puede usar rpc sobre tcp si desea distribuir los procesos a través de una red más adelante.
http://docs.python.org/dev/library/multiprocessing.html#exchanging-objects-between-processes
fuente
No está directamente relacionado con el multiprocesamiento per se, pero a partir de su ejemplo, parecería que podría usar el módulo de estantería o algo así. ¿El "big_lookup_object" realmente tiene que estar completamente en la memoria?
fuente
No, pero puede cargar sus datos como un proceso secundario y permitirle compartir sus datos con otros niños. vea abajo.
fuente
Para la plataforma Linux / Unix / MacOS, forkmap es una solución rápida y sucia.
fuente