python:使用多处理时访问变量的问题

Dee*_*epa 1 python class multiprocessing python-2.7 python-multiprocessing

我是 python 中多处理概念的新手,当我尝试在我的代码中包含多处理时,我在访问变量时遇到了问题。对不起,如果我听起来很天真,但我就是想不通。下面是我的场景的一个简单版本。

class Data:
    def __init__(self):
        self.data = "data"
    def datameth(self):
        print self.data
        print mainvar

class First:
    def __init__(self):
        self.first = "first"
    def firstmeth(self):
        d = Data()
        d.datameth()
        print self.first

def mymethod():
    f = First()
    f.firstmeth()

if __name__ == '__main__':
    mainvar = "mainvar"
    mymethod()
Run Code Online (Sandbox Code Playgroud)

当我运行它时,它运行良好并给出输出:

data
mainvar
first
Run Code Online (Sandbox Code Playgroud)

但是当我尝试mymethod()作为一个进程运行时

from multiprocessing import Process
class Data:
    def __init__(self):
        self.data = "data"
    def datameth(self):
        print self.data
        print mainvar

class First:
    def __init__(self):
        self.first = "first"
    def firstmeth(self):
        d = Data()
        #print mainvar
        d.datameth()
        print self.first


def mymethod():
    f = First()
    f.firstmeth()

if __name__ == '__main__':
    mainvar = "mainvar"
    #mymethod()
    p = Process(target = mymethod)
    p.start()
Run Code Online (Sandbox Code Playgroud)

我收到这样的错误:

NameError: global name 'mainvar' is not defined
Run Code Online (Sandbox Code Playgroud)

关键是,我无法mainvar从First班级或Data班级内部访问。我在这里缺少什么?

编辑:实际上在我的真实场景中,它不仅仅是声明 mainvar,它是经过一些处理的方法的返回值。

if __name__ == '__main__':
    ***some other stuff***
    mainvar = ***return value of some method**
    p = Process(target = mymethod)
    p.start()
Run Code Online (Sandbox Code Playgroud)

编辑 2:正如@dciriello 在评论中提到的,它在 Linux 中运行良好,但在 Windows 中却没有:(

dan*_*ano 6

这是 Windows 的限制,因为它不支持fork. 当一个子进程在 Linux 中被 fork 时,它会得到一个父进程状态的写时复制副本,所以mainvar你在里面定义的if __name__ == "__main__":将在那里。但是,在 Windows 上,子进程的状态是通过重新导入__main__程序模块来创建的。这意味着mainvar在孩子中不存在,因为它只在if __name__ == "__main__"守卫内部创建。因此,如果您需要mainvar在子进程内部进行访问,您唯一的选择是mymethod在Process构造函数中将其作为参数显式传递给子进程:

mainvar = "whatever"
p = Process(target=mymethod, args=(mainvar,))
Run Code Online (Sandbox Code Playgroud)

multiprocessing文档中提到了这种最佳实践:

显式地将资源传递给子进程

在 Unix 上,子进程可以使用在使用全局资源的父进程中创建的共享资源。但是,最好将对象作为参数传递给子进程的构造函数。

除了使代码(可能)与 Windows 兼容之外,这还确保只要子进程仍然存在,对象就不会在父进程中被垃圾收集。

请注意粗体部分 - 虽然它没有完全说明,但它有助于 Windows 兼容性的原因是因为它有助于避免您看到的确切问题。

这也包含在文档的部分中,该部分专门讨论了由于缺少以下内容而导致的 Windows 限制fork:

全局变量

请记住,如果在子进程中运行的代码尝试访问全局变量,那么它看到的值(如果有)可能与Process.start调用时父进程中的值不同。

然而,只是模块级常量的全局变量不会引起任何问题。

注意“如果有”。因为您的全局变量是在if __name__ == "__main__":警卫内部声明的,所以它甚至不会出现在孩子中。