是否将共享只读数据复制到不同进程以进行多处理?

时间:2011-04-05 08:31:29

标签: python numpy multiprocessing

我看到的这段代码看起来像这样:

glbl_array = # a 3 Gb array

def my_func( args, def_param = glbl_array):
    #do stuff on args and def_param

if __name__ == '__main__':
  pool = Pool(processes=4)
  pool.map(my_func, range(1000))

有没有办法确保(或鼓励)不同的进程没有获得glbl_array的副本但是共享它。如果没有办法停止复制,我将使用memmapped数组,但我的访问模式不是很规律,所以我希望memmapped数组更慢。以上似乎是第一个尝试的事情。这是在Linux上。我只是想从Stackoverflow获得一些建议,并且不想惹恼系统管理员。如果第二个参数是真正的不可变对象,如glbl_array.tostring()

,您认为它会有所帮助吗?

4 个答案:

答案 0 :(得分:99)

您可以非常轻松地使用multiprocessing和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 __name__ == '__main__':
    pool = multiprocessing.Pool(processes=4)
    pool.map(my_func, range(10))

    print shared_array

打印

[[ 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.]]

但是,Linux在fork()上具有写时复制语义,因此即使不使用multiprocessing.Array,除非写入数据,否则不会复制数据。

答案 1 :(得分:4)

以下代码适用于Win7和Mac(可能在Linux上,但未经过测试)。

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 __name__ == '__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

答案 2 :(得分:2)

对于那些使用Windows而不支持fork()的人(除非使用CygWin),pv的答案不起作用。全球不适用于子进程。

相反,您必须在Pool / Process的初始值设定项中传递共享内存:

#! /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 __name__ == '__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()

(它并不是numpy而且它不是很好的代码,但它说明了这一点; - )

答案 3 :(得分:0)

如果您正在寻找一种在Windows上高效运行的选项,并且适用于不规则访问模式,分支以及您可能需要基于共享内存矩阵和流程的组合分析不同矩阵的其他方案 - 本地数据,ParallelRegression包中的mathDict工具包旨在处理这种情况。