【问题标题】:Multiprocessing output differs between Linux and Windows - Why?Linux 和 Windows 之间的多处理输出不同 - 为什么?
【发布时间】:2017-09-28 13:20:18
【问题描述】:

我正在尝试将共享密钥传递给子进程。在 Linux 环境中,这是可行的。在 Windows 环境中,孩子不会收到共享密钥。下面的三个文件是我正在尝试做的一个简单示例:

main.py

import multiprocessing
import module1
import module2

if __name__ == "__main__":
    module1.init()
    process = multiprocessing.Process(target=module2.start)
    process.start()
    process.join()

module1.py

import ctypes
import multiprocessing

x = None

def init():
    global x
    x = multiprocessing.Value(ctypes.c_wchar_p, "asdf")

module2.py

import module1

def start():
    print(module1.x.value)

在 Ubuntu 14.04 环境中,在 Python 3.5 上,我收到以下输出:

$ python3 main.py
asdf

在 CentOS 7 环境中,我收到以下输出:

$ python3 main.py
asdf

在 Windows 10 上使用适用于 Linux 的 Windows 子系统(在 Creator 更新之前和之后,因此 Ubuntu 14.04 和 16.04)我得到以下输出:

$ python3 main.py
asdf

但是,在 Windows 7 和 Windows 10 环境中,使用 3.5 或 3.6,我得到一个 AttributeError 而不是上面的输出:

Process Process-1:
Traceback (most recent call last):
  File "C:\Python\Python35\lib\multiprocessing\process.py", line 249, in _bootstrap
    self.run()
  File "C:\Python\Python35\lib\multiprocessing\process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "H:\Development\replicate-bug\module2.py", line 5, in start
    print(module1.x.value)
AttributeError: 'NoneType' object has no attribute 'value'

我正在使用shared ctype。这个值应该被子进程继承。

为什么我在 Windows 环境中收到此AttributeError,但在 Linux 环境中却没有?

【问题讨论】:

    标签: python linux windows python-multiprocessing attributeerror


    【解决方案1】:

    正如其中一篇帖子 automatically linked on the sidebar 中所述,Windows 在 *NIX 系统上没有 fork 系统调用。

    这意味着 Windows 子进程基本上是完全独立的,而不是共享全局状态(就像 NIX 进程可以做的那样)。这包括模块。

    怀疑正在发生的事情是模块被重新加载,而您在 module2.start 中访问的 module1 并不是您所期望的模块。

    multiprocessing guidelines 明确提到模块级常量不受规则约束:“变量可能不包含您期望的内容”。好吧,无论哪种情况,解决方案都是将您想要的模块显式传递给子进程,如下所示:

    模块 2

    def start(mod1):
        print(mod1.x.value)
    

    main.py

    if __name__ == '__main__':
        module1.init()
        process = multiprocessing.Process(target=module2.start, args=(module1,))
        process.start()
        process.join()
    

    【讨论】:

    • 实际上,解决方案是在 main.py 中声明 x = multiprocessing.Value(ctypes.c_wchar_p, "asdf") 并将其作为参数传递给子进程(完全取消 module1,除非需要未显示的功能示例)。
    • @Mego 有这样的需求
    • @ArtOfCode 在这种情况下,也可以通过module1.init() 将其传递给module1。然后,两个进程都会正确引用共享对象。
    • 这实际上只是将指针复制到共享内存还是腌制它指向的整个对象(spawn 通常是这样工作的)
    • @quartata 文档没有涉及语义...run pydoc 仅表示使用给定的 args 和 kwargs 调用目标。目前尚不清楚这些是腌制还是通过引用传递
    猜你喜欢
    • 2019-06-13
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 1970-01-01
    相关资源
    最近更新 更多