【问题标题】:Python multiprocessing linux windows differencePython 多处理 linux windows 区别
【发布时间】:2017-02-09 22:47:04
【问题描述】:

此代码在 linux 上执行但抛出 AttributeError: type object 'T' has no attribute 'val' on windows,为什么?

from multiprocessing import Process
import sys

class T():
    @classmethod
    def init(cls, val):
        cls.val = val

def f():
    print(T.val)

if __name__ == '__main__':
    T.init(5)

    f()

    p = Process(target=f, args=())
    p.start()

【问题讨论】:

    标签: python linux windows multiprocessing cross-platform


    【解决方案1】:

    Windows 缺少fork() 系统调用,它复制了当前进程。这有很多含义,包括在windows multiprocessing 文档页面上列出的那些。更具体地说:

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

    在内部,python 通过从头开始一个新进程并告诉它再次加载所有模块来在 windows 上创建一个新进程。因此,您在当前流程中所做的任何更改都不会被看到。

    在您的示例中,这意味着在子进程中,您的模块将被加载,但 if __name__ == '__main__' 部分将不会运行。所以T.init 将不会被调用,T.val 将不存在,因此您看到的错误。

    另一方面,在 POSIX 系统(包括 Linux)上,进程创建使用 fork,并且所有全局状态都保持不变。子进程运行所有内容的副本,因此它不必重新加载任何内容,并且会看到其 T 的副本及其 val 的副本。

    这也意味着在 POSIX 系统上,进程创建速度更快,资源消耗也更轻,尤其是当“复制”使用写时复制来避免实际复制数据的开销时。

    在使用多处理时还有其他一些怪癖,所有这些都在python multiprocessing guidelines中有详细说明。

    【讨论】:

    • fork vs spawn 是一个非常古老的辩论。 NT 内核一直有能力进行写时复制分叉,但来自 MS-DOS 的 Windows API 本身不允许这样做。此外,fork 多线程进程也存在一些不小的问题,在这种情况下,Python 3.4 除了“fork”之外还为您提供了两个启动选项:“forkserver”和“spawn”。后者是 Windows 上的唯一选项。
    • 确实如此。尽管 NT 内核中存在底层功能,但我总是发现奇怪的是 Win32 中没有可用的 fork 系统调用。我不禁将其视为微软不愿屈服于旧的“那些不了解 Unix 的人注定要重新发明它” 的说法。哎呀,他们等到 W2k8 才最终添加符号链接。我准备打赌在未来的某些 Windows 版本中会有一个fork()-equivalent,只要给他们时间。可能有一个名字,比如DuplicateCurrentProcess
    • 我的意思是不允许它是系统从在 DOS 上运行的 Windows 2.0 演变而来的方式,它不适用于fork——至少不适用于活动进程。内核模式 Windows (win32k.sys) 扩展了 NT EPROCESSETHREAD 结构,而 fork 可能会出现问题,例如死锁。 OTOH,为了分析流程,我们确实有能力派生一个惰性snapshot
    • @spectras:在 Windows 中没有 fork() 等价物,因为它周围有未解决的问题。在单线程进程的情况下它可能工作得非常好(这是发明时唯一的一种进程),但在考虑多线程时情况并非如此。从本质上讲,它增加了支持的数量调用而不提供任何附加值。无论您使用 fork() 做什么,都有更好的方法来解决 Windows 上的相同问题(例如服务与守护程序)。
    • @IInspectable> 很好,NT 内核支持它并且在使用其他子系统时可用:“the Windows kernel has supported “fork” for a long time (going back to earlier POSIX and SFU application support), but it is not exposed in the Win32 programming model”。线程可以放在一边,理由是进程必须选择 one fork 和线程(基本上是 POSIX 线程发生的情况)。至于为什么,eryksun 的解释是有道理的,虽然我很想知道具体细节。
    猜你喜欢
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    • 2020-12-01
    • 2020-07-22
    • 2011-07-12
    相关资源
    最近更新 更多