Python 多处理 linux windows 区别

sha*_*ane 5 python linux windows cross-platform multiprocessing

此代码在 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()
Run Code Online (Sandbox Code Playgroud)

spe*_*ras 5

Windows 缺少fork()复制当前进程的系统调用。这有很多含义,包括在windows 多处理文档页面上列出的那些。进一步来说:

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

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

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

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

这也意味着进程创建在 POSIX 系统上的资源上更快、更轻,特别是因为“复制”使用写时复制来避免实际复制数据的开销。

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

  • “fork” 与 “spawn” 是一个非常古老的争论。NT 内核始终具有进行写时复制分叉的能力,但源自 MS-DOS 的 Windows API 本身不允许这样做。此外,分叉多线程进程也存在一些不小的问题,在这种情况下,Python 3.4 除了“fork”之外还为您提供了两个启动选项:“forkserver”和“spawn”。后者是 Windows 上的唯一选项。 (2认同)
  • 确实是。尽管 NT 内核中存在底层功能,但我总是发现 Win32 中没有可用的 fork 系统调用是很奇怪的。我不禁将其视为微软不愿屈服于旧的 *“不了解 Unix 的人注定要重新发明它”* 的说法。哎呀,他们等到 W2k8 才最终添加符号链接。我敢打赌,在未来的某些 Windows 版本中会有一个 `fork()` 等价物,给他们时间。可能有一个名字,比如“DuplicateCurrentProcess”。 (2认同)