Me gustaría usar una matriz numpy en memoria compartida para usar con el módulo de multiprocesamiento. La dificultad es usarlo como una matriz numpy, y no solo como una matriz ctypes.
from multiprocessing import Process, Array
import scipy
def f(a):
a[0] = -a[0]
if __name__ == '__main__':
# Create the array
N = int(10)
unshared_arr = scipy.rand(N)
arr = Array('d', unshared_arr)
print "Originally, the first two elements of arr = %s"%(arr[:2])
# Create, start, and finish the child processes
p = Process(target=f, args=(arr,))
p.start()
p.join()
# Printing out the changed values
print "Now, the first two elements of arr = %s"%arr[:2]
Esto produce resultados como:
Originally, the first two elements of arr = [0.3518653236697369, 0.517794725524976]
Now, the first two elements of arr = [-0.3518653236697369, 0.517794725524976]
Se puede acceder a la matriz de una manera ctypes, por ejemplo, arr[i]
tiene sentido. Sin embargo, no es una matriz numerosa y no puedo realizar operaciones como -1*arr
, o arr.sum()
. Supongo que una solución sería convertir la matriz ctypes en una matriz numpy. Sin embargo (además de no poder hacer que esto funcione), no creo que se comparta más.
Parece que habría una solución estándar para lo que tiene que ser un problema común.
python
numpy
multiprocessing
shared
Ian Langmore
fuente
fuente
subprocess
lugar demultiprocessing
.Respuestas:
Para agregar a las respuestas de @ unutbu (ya no está disponible) y @Henry Gomersall. Puede utilizar
shared_arr.get_lock()
para sincronizar el acceso cuando sea necesario:Ejemplo
Si no necesita acceso sincronizado o crea sus propias cerraduras, entonces no
mp.Array()
es necesario. Podrías usarmp.sharedctypes.RawArray
en este caso.fuente
count
anumpy.frombuffer()
. Puede intentar hacerlo en un nivel inferior usandommap
o algo comoposix_ipc
directamente para implementar un análogo de RawArray redimensionable (podría implicar copiar mientras redimensiona) (o buscar una biblioteca existente). O si su tarea lo permite: copie los datos en partes (si no los necesita todos a la vez). "Cómo cambiar el tamaño de una memoria compartida" es una buena pregunta aparte.Pool()
define el número de procesos (el número de núcleos de CPU disponibles se utiliza por defecto).M
es el número de vecesf()
que se llama a la función.El
Array
objeto tiene unget_obj()
método asociado con él, que devuelve la matriz ctypes que presenta una interfaz de búfer. Creo que lo siguiente debería funcionar ...Cuando se ejecuta, imprime el primer elemento de
a
ahora 10.0, mostrandoa
yb
son solo dos vistas en la misma memoria.Para asegurarse de que todavía es seguro para multiprocesador, creo que tendrá que usar los métodos
acquire
yrelease
que existen en elArray
objetoa
, y su bloqueo integrado para asegurarse de que se acceda a todo de manera segura (aunque no soy un experto en el módulo multiprocesador).fuente
mp.Array
.Si bien las respuestas ya dadas son buenas, hay una solución mucho más fácil a este problema siempre que se cumplan dos condiciones:
En este caso, no es necesario jugar con la creación explícita de variables compartidas, ya que los procesos secundarios se crearán mediante una bifurcación. Un niño bifurcado comparte automáticamente el espacio de memoria de los padres. En el contexto del multiprocesamiento de Python, esto significa que comparte todas las variables de nivel de módulo ; tenga en cuenta que esto no es válido para los argumentos que pasa explícitamente a sus procesos secundarios o a las funciones que llama en a
multiprocessing.Pool
o así.Un simple ejemplo:
fuente
Escribí un pequeño módulo de Python que usa la memoria compartida POSIX para compartir matrices numpy entre intérpretes de Python. Quizás le resulte útil.
https://pypi.python.org/pypi/SharedArray
Así es como funciona:
fuente
Puede utilizar el
sharedmem
módulo: https://bitbucket.org/cleemesser/numpy-sharedmemEntonces, aquí está su código original, esta vez usando memoria compartida que se comporta como una matriz NumPy (tenga en cuenta la última declaración adicional que llama a una
sum()
función NumPy ):fuente