import multiprocessing
import numpy as np
import multiprocessing as mp
import ctypes
class Test():
def __init__(self):
shared_array_base = multiprocessing.Array(ctypes.c_double, 100, lock=False)
self.a = shared_array = np.ctypeslib.as_array(shared_array_base)
def my_fun(self,i):
self.a[i] = 1
if __name__ == "__main__":
num_cores = multiprocessing.cpu_count()
t = Test()
def my_fun_wrapper(i):
t.my_fun(i)
with mp.Pool(num_cores) as p:
p.map(my_fun_wrapper, np.arange(100))
print(t.a)
在上面的代码中,我试图使用 multiprocessing
编写代码以修改数组。在每个过程中执行的函数 my_fun()
应该修改索引 a[:]
<下的数组 i
的值/ strong>作为参数传递给my_fun()
。关于上面的代码,我想知道正在复制什么。
1)每个进程都在复制代码中的任何内容吗?我认为对象可能是,但理想情况下什么也不是。
2)有没有一种方法可以对对象使用包装函数my_fun()
?
答案 0 :(得分:2)
除了用multiprocessing.Array
分配的共享内存外,几乎所有代码都将被复制。 multiprocessing
充满了不直观的隐式副本。
当您在multiprocessing
中生成新流程时,新流程几乎需要原始流程中所有内容的版本。根据平台和设置的不同,处理方式也有所不同,但是我们可以告诉您使用的是“ fork”模式,因为您的代码无法在“ spawn”或“ forkserver”模式下工作-您会收到有关错误的错误信息能够找到my_fun_wrapper
。 (Windows仅支持“ spawn”,因此我们可以告诉您不在Windows上。)
在“分叉”模式下,此初始副本是通过使用fork
系统调用来要求操作系统本质上复制整个过程以及内部所有内容的。由multiprocessing.Array
分配的内存属于“外部”内存,不会被复制,但是大多数其他东西都是。 (还有写时复制优化,但是写时复制仍然像复制所有内容一样工作,并且由于引用计数更新,该优化在Python中效果不佳。)
将任务分派到工作进程时,multiprocessing
需要制作更多副本。任何参数以及任务本身的可调用对象都是主流程中的对象,而对象固有地仅存在于一个流程中。工人无法访问任何一个。他们需要自己的版本。 multiprocessing
通过腌制可调用对象和参数,通过进程间通信发送序列化的字节并在工作人员中腌制腌菜来处理第二轮副本。
当主泡菜my_fun_wrapper
时,泡菜只会说“在my_fun_wrapper
模块中寻找__main__
函数,而工作人员会查询他们的my_fun_wrapper
版本解开它。 my_fun_wrapper
寻找全局t
,在工作进程中,t
由fork产生,而fork产生t
,其数组由共享内存支持您分配了原始multiprocessing.Array
通话。
另一方面,如果您尝试将t.my_fun
传递给p.map
,则multiprocessing
必须腌制和释放方法对象。所得的pickle不会说“查找t
全局变量并获取其my_fun
方法”。泡菜说要构建一个 new Test
实例并获取 its my_fun
方法。泡菜没有任何有关使用分配的共享内存的说明,并且生成的Test
实例及其数组与您要修改的原始数组无关。
我知道没有什么好方法可以避免需要某种包装函数。