我对多处理有点新意。但是,假设我们有一个程序如下。该程序似乎工作正常。现在回答这个问题。在我看来,我们将同时拥有4个SomeKindOfClass
同名(a
)的实例。怎么可能?此外,这种编程是否存在潜在风险?
from multiprocessing.dummy import Pool
import numpy
from theFile import someKindOfClass
n = 8
allOutputs = numpy.zeros(n)
def work(index):
a = SomeKindOfClass()
a.theSlowFunction()
allOutputs[index] = a.output
pool = Pool(processes=4)
pool.map(work,range(0,n))
答案 0 :(得分:3)
名称a
仅在work
函数的范围内是本地的,因此此处不存在名称冲突。内部python将使用唯一标识符跟踪每个类实例。如果您想检查这个,可以使用id
函数检查对象ID:
print(id(a))
我发现您的代码没有任何问题。
答案 1 :(得分:2)
实际上,您将8
个SomeKindOfClass
个实例(每个工作一个),但只有4个同时处于活动状态。
multiprocessing
vs multiprocessing.dummy
只有继续使用multiprocessing.dummy
模块时,您的程序才有效,该模块只是threading
模块的包装器。你还在使用" python线程" (不是单独的过程)。 " Python线程"共享同一个全球国家; "流程"别'吨。 Python线程也共享相同的GIL,因此它们仍然限于一次运行一个python字节码语句,这与可以同时运行python代码的进程不同。
如果您要将导入更改为from multiprocessing import Pool
,您会注意到allOutputs
数组在所有工作人员完成执行后仍然保持不变(同样,您可能会收到错误,因为您'在全局范围内重新创建池,您应该将其放在main()
函数中。这是因为multiprocessing
在创建新进程时创建了整个全局状态的新副本。当工作人员修改全局allOutputs
时,它将修改该初始全局状态的副本。当流程结束时,不会将任何内容返回到主流程,主流程的全局状态将保持不变。
与线程不同,进程不共享相同的内存
如果要在进程之间共享状态,则必须显式声明共享变量并将它们传递给每个进程,或者使用管道或其他方法来允许工作进程相互通信或与主进程通信。 / p>
有几种方法可以做到这一点,但也许最简单的方法是使用Manager
类
import multiprocessing
def worker(args):
index, array = args
a = SomeKindOfClass()
a.some_expensive_function()
array[index] = a.output
def main():
n = 8
manager = multiprocessing.Manager()
array = manager.list([0] * n)
pool = multiprocessing.Pool(4)
pool.map(worker, [(i, array) for i in range(n)])
print array
答案 2 :(得分:1)
您可以在池工作者中声明类实例,因为每个实例在内存中都有一个单独的位置,因此它们不会发生冲突。问题是如果您先声明一个类实例,然后尝试将该实例传递给多个池工作者。然后每个工作者都有一个指向内存中相同位置的指针,它将失败(这可以处理,但不是这样)。
基本上,池工作者不能在任何地方重叠内存。只要工作人员不尝试在某处共享内存,或执行可能导致冲突的操作(如打印到同一文件),就不会有任何问题。
确保他们应该做的事情(比如想要打印到文件中的内容,或者添加到某个更广泛的命名空间)最后返回结果,然后迭代完毕。
答案 3 :(得分:1)
如果您使用多处理,则不必担心 - 进程不共享内存(默认情况下)。因此,拥有类SomeKindOfClass
的几个独立对象没有任何风险 - 每个对象都将存在于自己的进程中。这个怎么运作? Python运行您的程序,之后它运行4个子进程。这就是为什么在if __init__ == '__main__'
之前进行pool.map(work,range(0,n))
构建非常重要的原因。否则,您将收到无限循环的流程创建。
问题可能是SomeKindOfClass
在磁盘上保持状态 - 例如,写入文件或读取它。