Estoy tratando de encontrar una manera de compartir la memoria entre los procesos de python. Básicamente, existen objetos que múltiples procesos de Python necesitan poder LEER (solo leer) y usar (sin mutación). En este momento, esto se implementa usando redis + strings + cPickle, pero cPickle requiere un tiempo precioso de CPU, por lo que me gustaría no tener que usarlo. La mayoría de las implementaciones de memoria compartida de Python que he visto en Internet parecen requerir archivos y encurtidos, que es básicamente lo que ya estoy haciendo y exactamente lo que estoy tratando de evitar.
Lo que me pregunto es si habría una manera de escribir un me gusta… básicamente una base de datos/servidor de objetos python en memoria y un módulo C correspondiente para interactuar con la base de datos.
Básicamente, el módulo C le pediría al servidor una dirección para escribir un objeto, el servidor respondería con una dirección, luego el módulo escribiría el objeto y notificaría al servidor que un objeto con una clave dada fue escrito en el disco en el momento ubicación especificada. Luego, cuando cualquiera de los procesos quisiera recuperar un objeto con una clave dada, simplemente le pediría a la base de datos la ubicación de memoria para la clave dada, el servidor respondería con la ubicación y el módulo sabría cómo cargar ese espacio en la memoria y transfiera el objeto python de vuelta al proceso python.
¿Es eso totalmente irrazonable o simplemente muy difícil de implementar? ¿Estoy persiguiendo algo que es imposible? Cualquier sugerencia será bienvenida. gracias internet
Desde Python 3.8 y en adelante puedes usar multiprocesamiento.memoria_compartida.MemoriaCompartida
No irrazonable.
IPC se puede hacer con un archivo mapeado en memoria. Python tiene una funcionalidad integrada:
http://docs.python.org/library/mmap.html
Simplemente mmap el archivo en ambos procesos y listo, tiene un archivo compartido. Por supuesto, tendrá que sondearlo en ambos procesos para ver qué cambios. Y tendrás que cooperar escribe entre ambos. Y decida en qué formato quiere poner sus datos. Pero es una solución común a su problema.
-
Pero esto aún requeriría serializar a bytes, ¿sí? El OP dijo que estaba tratando de evitar eso.
–Ned Batchelder
2 de julio de 2012 a las 23:49
-
Esto sería algún tipo de serialización, sí. Quizás la serialización personalizada haría un mejor trabajo si se conoce el tipo de objeto. Alternativamente, incluya un código hash para evitar volver a deserializar un objeto dos veces. Sin embargo, se hace esto, se requiere serialización.
– José
2 de julio de 2012 a las 23:54
-
¿Está seguro? Network + redis sería comparativamente caro. ¿Por qué no perfilarlo?
– José
3 de julio de 2012 a las 0:28
-
Redis se está ejecutando en la máquina, no es un servidor Redis de red
– nickneedsaname
3 de julio de 2012 a las 1:04
-
Aún así, lo estás haciendo a través de un socket de dominio o un socket TCP local, ¿verdad?
– José
3 de julio de 2012 a las 6:11
Si no quieres encurtir, multiprocessing.sharedctypes
podría encajar Sin embargo, es un poco de bajo nivel; obtiene valores individuales o matrices de tipos específicos.
Otra forma de distribuir datos a procesos secundarios (una forma) es multiprocessing.Pipe
. Eso puede manejar objetos de Python y está implementado en C, por lo que no puedo decirle si usa decapado o no.
Ying
Python NO admite memoria compartida entre procesos independientes. Puede implementar el suyo propio en lenguaje C, o usar SharedArray
si está trabajando con libsvm, numpy.ndarray, scipy.sparse.
pip install SharedArray
def test ():
def generateArray ():
print('generating')
from time import sleep
sleep(3)
return np.ones(1000)
a = Sarr('test/1', generateArray)
# use same memory as a, also work in a new process
b = Sarr('test/1', generateArray)
c = Sarr('test/1', generateArray)
import re
import SharedArray
import numpy as np
class Sarr (np.ndarray):
def __new__ (self, name, getData):
if not callable(getData) and getData is None:
return None
self.orig_name = name
shm_name="shm://" + re.sub(r'[./]', '_', name)
try:
shm = SharedArray.attach(shm_name)
print('[done] reuse shared memory:', name)
return shm
except Exception as err:
self._unlink(shm_name)
data = getData() if callable(getData) else getData
shm = SharedArray.create(shm_name, data.size)
shm[:] = data[:]
print('[done] loaded data to shared memory:', name)
return shm
def _unlink (name):
try:
SharedArray.delete(name[len('shm://'):])
print('deleted shared memory:', name)
except:
pass
if __name__ == '__main__':
test()
¿Exactamente cuán valioso es el tiempo de su CPU que vale la pena deshacerse de una solución funcional que es mucho menos complicada de mantener sincronizada que la que está proponiendo? Lo que estás pidiendo se puede hacer, pero será un gran dolor en el culo hacerlo. correctamente.
– milimoose
2 de julio de 2012 a las 23:50
El tiempo de CPU es el más preciado. Básicamente, decapar objetos puede tomar entre 20 ms (para uno pequeño) y 60 ms (para uno grande). Personalmente siento que estos dos tiempos son demasiado largos. EDITAR: Demasiado tiempo en el sentido de que tiene que haber una mejor manera, no es que crea que cPickle no se está esforzando lo suficiente.
– nickneedsaname
3 de julio de 2012 a las 0:29
Compartir la memoria sería factible, pero compartir objetos será muy difícil… Puede encontrar una pregunta relacionada aquí: stackoverflow.com/questions/1268252/… (hay un buen artículo de Alex Martelli explicando por qué esto es difícil).
– ChristopheD
3 de julio de 2012 a las 6:02
@f34r ¿Se sabe que el decapado es el principal o al menos un cuello de botella importante en su base de código actual? Si no, su tiempo de CPU es, de hecho, abundante. Es posible que pueda justificar la eliminación de Redis si sus datos no son realmente persistentes y reemplazarlos con solo enviar valores en escabeche directamente. Pero mi intuición es que no se puede tener una arquitectura distribuida “no compartir nada” sin mensajes serializados, y es mucho más fácil razonar sobre ellos que los sistemas de memoria compartida.
– milimoose
3 de julio de 2012 a las 9:48
Supongo que también podrías mirar en el compartir mecanismos de
multiprocessing
módulo. (La primera oración de esos párrafos recomienda no hacerlo, por supuesto).– milimoose
3 de julio de 2012 a las 9:54