Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么windows和linux上的全局对象和函数参数的multiprocessing.Process行为不同_Python_Multiprocessing - Fatal编程技术网

Python 为什么windows和linux上的全局对象和函数参数的multiprocessing.Process行为不同

Python 为什么windows和linux上的全局对象和函数参数的multiprocessing.Process行为不同,python,multiprocessing,Python,Multiprocessing,以下代码在windows和linux上运行时具有不同的输出(都使用python2.7) “test.py” 导入模拟 从多处理导入进程 A类(对象): 定义初始化(自): self.a=1 self.b=2 self.c=3 定义获取状态(自身): 打印“\uu获取状态” 返回{'a':self.a,'b':self.b, “c”:0} def func(): 导入\u mock.to\u mock=1 a=a() 归还 第1(a)款: 打印a.a,a.b,a.c 将导入\u mock.打印到\

以下代码在windows和linux上运行时具有不同的输出(都使用python2.7)

“test.py”
导入模拟
从多处理导入进程
A类(对象):
定义初始化(自):
self.a=1
self.b=2
self.c=3
定义获取状态(自身):
打印“\uu获取状态”
返回{'a':self.a,'b':self.b,
“c”:0}
def func():
导入\u mock.to\u mock=1
a=a()
归还
第1(a)款:
打印a.a,a.b,a.c
将导入\u mock.打印到\u mock
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
a=func()
p=进程(目标=func1,参数=(a,))
p、 开始()
p、 加入
在windows上,输出为:

\u获取状态__
1 2 0
没有一个
这正是我所期望的

在linux上,它是:

123
1.
不会克隆全局对象和传递的参数

我的问题是为什么他们的行为不同?如何使linux代码的行为与windows one相同?

在linux(以及其他类似Unix的操作系统)上,Python的
多处理
模块使用
fork()
创建有效继承父进程内存状态副本的新子进程。这意味着解释器不需要对作为
进程
参数
传递的对象进行pickle处理,因为子进程已经可以正常使用它们了

但是,Windows没有
fork()
系统调用,因此
多处理
模块需要做更多的工作才能使子生成过程正常工作。首先是基于
fork()
的实现,然后是非fork的Windows实现


值得注意的是,Python开发人员经常觉得,创建子进程与运行Python的平台有如此大的差异是有点不合适的。因此,在Python3.4中,添加了一个新的系统,允许您执行以下操作。选项有
“fork”
“forkserver”
“spawn”
“fork”
方法仍然是类Unix系统上的默认方法(在早期版本的Python中它是唯一的实现)。
“spawn”
方法是Windows上的默认(也是唯一)选项,但现在也可以在类似Unix的系统上使用。
“forkserver”
方法在某种程度上是两者的混合(并且仅在某些类似Unix的系统上可用)。您可以在文档中阅读有关方法之间差异的更多信息。

添加到@Blckknght的答案中:在Windows上,每个进程“从头开始”导入原始模块,而在Unix-y系统上,只有主进程运行整个模块,而所有其他进程都可以看到当时存在的任何模块。
fork()
用于创建新流程(不,您不是在调用
fork()
yourself-
multi-processing
internal在创建新流程时调用它)

具体而言,对于您的
导入\u mock

  • 在所有平台上,主进程调用
    func()
    ,将
    import\u mock.to\u mock
    设置为1

  • 在Unix-y平台上,所有新进程都会看到这一点:
    fork()
    发生在这之后,因此1是所有新进程继承的状态

  • 在Windows上,所有新进程“从头开始”运行整个模块。因此,他们各自导入自己的全新版本的
    import\u mock
    。只有主进程调用
    func()
    ,因此只有主进程看到
    to\u mock
    更改为1。所有其他进程都会看到fresh
    None
    状态

这一切都是意料之中的,实际上第二次很容易理解;-)

传递
a
的过程更微妙,因为它更依赖于
多处理
实现细节。该实现本来可以从一开始就选择在所有平台上pickle参数,但事实并非如此,现在在某些平台上进行更改而不破坏内容已经太晚了

由于写时复制
fork()
语义,在Unix-y系统上不需要pickle
Process()
参数,因此实现从未执行过。但是,如果没有
fork()
,就必须在Windows上对它们进行pickle处理,实现也是如此

Python3.4允许您在所有平台上强制执行“Windows实现”(
spawn
),在此之前,没有机械的方法可以避免可能的跨平台意外


但实际上,我很少被这件事困扰。例如,我知道多重处理在很大程度上依赖于酸洗,所以我完全不想在任何地方玩腌菜的把戏。传递
a()
实例时出现“问题”的唯一原因是,您正在玩pickle把戏(通过覆盖默认的
\uuu getstate\uuu()
)。

因为在两个操作系统上实现的方式不同。文档提到,在Windows上,来自多处理的许多类型需要可拾取,以便子进程可以使用它们。这意味着,在其他操作系统上,它们不必如此。登录
多处理
模块的文档可能有助于解决您的特定问题。此外,如果您的Tensorflow模型在进程内运行,并且能够在Windows而不是Linux上使用GPU,则这也是问题的解决方案。您可以使用
mp.set_start_method('spawn')
切换到
spawn
,因为在Win上启动进程的默认值是
spawn
,在Linux上启动进程的默认值是
fork
'''import_mock.py'''
to_mock = None