Le morceau de code que j'ai ressemble à ceci:
glbl_array = # a 3 Gb array
def my_func( args, def_param = glbl_array):
#do stuff on args and def_param
if __== '__main__':
pool = Pool(processes=4)
pool.map(my_func, range(1000))
Existe-t-il un moyen de s'assurer (ou d'encourager) que les différents processus n'obtiennent pas une copie de glbl_array mais la partagent. S'il n'y a aucun moyen d'arrêter la copie, j'irai avec un tableau memmappé, mais mes modèles d'accès ne sont pas très réguliers, donc je m'attends à ce que les tableaux memmappés soient plus lents. Ce qui précède semblait être la première chose à essayer. C'est sous Linux. Je voulais juste quelques conseils de Stackoverflow et je ne veux pas ennuyer le sysadmin. Pensez-vous que cela aidera si le second paramètre est un véritable objet immuable comme glbl_array.tostring()
.
Vous pouvez utiliser assez facilement la mémoire partagée de multiprocessing
avec Numpy:
import multiprocessing
import ctypes
import numpy as np
shared_array_base = multiprocessing.Array(ctypes.c_double, 10*10)
shared_array = np.ctypeslib.as_array(shared_array_base.get_obj())
shared_array = shared_array.reshape(10, 10)
#-- edited 2015-05-01: the assert check below checks the wrong thing
# with recent versions of Numpy/multiprocessing. That no copy is made
# is indicated by the fact that the program prints the output shown below.
## No copy was made
##assert shared_array.base.base is shared_array_base.get_obj()
# Parallel processing
def my_func(i, def_param=shared_array):
shared_array[i,:] = i
if __== '__main__':
pool = multiprocessing.Pool(processes=4)
pool.map(my_func, range(10))
print shared_array
qui imprime
[[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
[ 2. 2. 2. 2. 2. 2. 2. 2. 2. 2.]
[ 3. 3. 3. 3. 3. 3. 3. 3. 3. 3.]
[ 4. 4. 4. 4. 4. 4. 4. 4. 4. 4.]
[ 5. 5. 5. 5. 5. 5. 5. 5. 5. 5.]
[ 6. 6. 6. 6. 6. 6. 6. 6. 6. 6.]
[ 7. 7. 7. 7. 7. 7. 7. 7. 7. 7.]
[ 8. 8. 8. 8. 8. 8. 8. 8. 8. 8.]
[ 9. 9. 9. 9. 9. 9. 9. 9. 9. 9.]]
Cependant, Linux a une sémantique de copie sur écriture sur fork()
, donc même sans utiliser multiprocessing.Array
, Les données ne seront pas copiées sauf si elles sont écrites.
Le code suivant fonctionne sur Win7 et Mac (peut-être sur Linux, mais non testé).
import multiprocessing
import ctypes
import numpy as np
#-- edited 2015-05-01: the assert check below checks the wrong thing
# with recent versions of Numpy/multiprocessing. That no copy is made
# is indicated by the fact that the program prints the output shown below.
## No copy was made
##assert shared_array.base.base is shared_array_base.get_obj()
shared_array = None
def init(shared_array_base):
global shared_array
shared_array = np.ctypeslib.as_array(shared_array_base.get_obj())
shared_array = shared_array.reshape(10, 10)
# Parallel processing
def my_func(i):
shared_array[i, :] = i
if __== '__main__':
shared_array_base = multiprocessing.Array(ctypes.c_double, 10*10)
pool = multiprocessing.Pool(processes=4, initializer=init, initargs=(shared_array_base,))
pool.map(my_func, range(10))
shared_array = np.ctypeslib.as_array(shared_array_base.get_obj())
shared_array = shared_array.reshape(10, 10)
print shared_array
Pour ceux qui sont bloqués avec Windows, qui ne prend pas en charge fork()
(à moins d'utiliser CygWin), la réponse de pv ne fonctionne pas. Les globaux ne sont pas mis à la disposition des processus enfants.
Au lieu de cela, vous devez transmettre la mémoire partagée lors de l'initialisation de Pool
/Process
comme telle:
#! /usr/bin/python
import time
from multiprocessing import Process, Queue, Array
def f(q,a):
m = q.get()
print m
print a[0], a[1], a[2]
m = q.get()
print m
print a[0], a[1], a[2]
if __== '__main__':
a = Array('B', (1, 2, 3), lock=False)
q = Queue()
p = Process(target=f, args=(q,a))
p.start()
q.put([1, 2, 3])
time.sleep(1)
a[0:3] = (4, 5, 6)
q.put([4, 5, 6])
p.join()
(ce n'est pas numpy et ce n'est pas du bon code mais ça illustre le point ;-)
Si vous recherchez une option qui fonctionne efficacement sous Windows et fonctionne bien pour les modèles d'accès irréguliers, les branchements et d'autres scénarios dans lesquels vous devrez peut-être analyser différentes matrices en fonction d'une combinaison d'une matrice de mémoire partagée et de données locales de processus, la boîte à outils mathDict du package ParallelRegression a été conçue pour gérer cette situation exacte.