python multiprocessing:设置类属性值

nit*_*tin 4 python multiprocessing

我有一个名为实验的课程和另一个名为案例的课程。一项实验是由许多个别案例组成的。请参阅下面的类定义,

from multiprocessing import Process

class Experiment (object):
    def __init__(self, name):
        self.name = name
        self.cases = []
        self.cases.append(Case('a'))
        self.cases.append(Case('b'))
        self.cases.append(Case('c'))

    def sr_execute(self):
        for c in self.cases:  
            c.setVars(6)

class Case(object):
    def __init__(self, name):
        self.name = name
    def setVars(self, var):
        self.var = var
Run Code Online (Sandbox Code Playgroud)

在我的实验类中,我有一个名为 sr_execute 的函数。该函数显示了所需的行为。我有兴趣解析所有案例并为每个案例设置一个属性。当我运行以下代码时,

if __name__ == '__main__':
    #multiprocessing.freeze_support()
    e = Experiment('exp')
    e.sr_execute()
    for c in e.cases: print c.name, c.var
Run Code Online (Sandbox Code Playgroud)

我明白了,

a 6
b 6
c 6
Run Code Online (Sandbox Code Playgroud)

这是期望的行为。

但是,我想使用多处理并行执行此操作。为此,我将 mp_execute() 函数添加到实验类中,

    def mp_execute(self):
        processes = []
        for c in self.cases: 
            processes.append(Process(target= c.setVars, args = (6,)))
        [p.start() for p in processes]
        [p.join() for p in processes]
Run Code Online (Sandbox Code Playgroud)

然而,这是行不通的。当我执行以下命令时,

if __name__ == '__main__':
    #multiprocessing.freeze_support()
    e = Experiment('exp')
    e.mp_execute()
    for c in e.cases: print c.name, c.var
Run Code Online (Sandbox Code Playgroud)

我收到一个错误,

AttributeError: 'Case' object has no attribute 'var'
Run Code Online (Sandbox Code Playgroud)

显然,我无法使用多处理设置类属性。

任何线索都发生了什么,

Bak*_*riu 6

你打电话时:

def mp_execute(self):
    processes = []
    for c in self.cases: 
        processes.append(Process(target= c.setVars, args = (6,)))
    [p.start() for p in processes]
    [p.join() for p in processes]
Run Code Online (Sandbox Code Playgroud)

当您创建它时Process,它将使用对象的副本,并且对该对象的修改不会传递到主程序,因为不同的进程具有不同的地址空间。如果您使用 s ,那么它会起作用,Thread因为在这种情况下不会创建副本。

另请注意,您的代码在 Windows 中可能会失败,因为您正在传递一个方法,target而 Windows 要求该方法target可挑选(并且实例方法不可挑选)。它target应该是在模块顶层定义的函数,以便在所有操作系统上工作。

如果您想向主进程传达更改,您可以:

  • 使用 aQueue传递结果
  • 使用 aManager构建共享对象

无论如何,您必须Queue通过设置“通道”(如)或设置共享状态来“显式”处理通信。


风格注释:不要以这种方式使用列表推导式:

[p.join() for p in processes]
Run Code Online (Sandbox Code Playgroud)

这根本就是错误的。您只是在浪费空间来创建 s 列表None。与正确的方法相比,它也可能更慢:

for p in processes:
    p.join()
Run Code Online (Sandbox Code Playgroud)

因为它必须将元素附加到列表中。

然而,有人说列表推导式比for循环稍快:

  • 性能差异非常小,通常并不重要
  • 当且仅当您考虑这种循环时它们才会更快:

    a = []
    for element in something:
        a.append(element)
    
    Run Code Online (Sandbox Code Playgroud)

    如果循环(如本例所示)不创建,list则for循环会更快。

顺便说一句:有些以map同样的方式使用会产生副作用。这又是错误的,因为与以前相同的原因,你不会获得太多的速度,并且它在map返回迭代器的 python3 中完全失败,因此它根本不会执行函数,从而使代码的可移植性较差。