在python中使用池进行多处理:关于同时具有相同名称的多个实例

时间:2016-06-15 14:49:28

标签: python memory multiprocessing pool

我对多处理有点新意。但是,假设我们有一个程序如下。该程序似乎工作正常。现在回答这个问题。在我看来,我们将同时拥有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))

4 个答案:

答案 0 :(得分:3)

名称a仅在work函数的范围内是本地的,因此此处不存在名称冲突。内部python将使用唯一标识符跟踪每个类实例。如果您想检查这个,可以使用id函数检查对象ID:

print(id(a))

我发现您的代码没有任何问题。

答案 1 :(得分:2)

实际上,您将8SomeKindOfClass个实例(每个工作一个),但只有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在磁盘上保持状态 - 例如,写入文件或读取它。