【问题标题】:Difference in behavior between os.fork and multiprocessing.Processos.fork 和 multiprocessing.Process 之间的行为差​​异
【发布时间】:2014-07-25 08:51:16
【问题描述】:

我有这个代码:

import os

pid = os.fork()

if pid == 0:
    os.environ['HOME'] = "rep1"
    external_function()
else:
    os.environ['HOME'] = "rep2"
    external_function()

还有这段代码:

from multiprocessing import Process, Pipe

def f(conn):
    os.environ['HOME'] = "rep1"
    external_function()
    conn.send(some_data)
    conn.close()

if __name__ == '__main__':
    os.environ['HOME'] = "rep2"
    external_function()
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print parent_conn.recv()
    p.join()

external_function 通过在环境变量HOME 中找到的目录中创建必要的子目录来初始化外部程序。这个函数在每个进程中只执行一次。

第一个示例使用os.fork(),目录按预期创建。但是对于使用multiprocessing 的第二个示例,只会创建rep2 中的目录。

为什么第二个示例不在rep1rep2 中创建目录?

【问题讨论】:

  • 我无法重现您看到的问题。我写了一个external_function 像这样:def external_function(): print os.environ['HOME'],并发现multiprocessing 示例打印出的正是我所期望的; 'rep1', 'rep2' 和我从conn.send 发回的字符串都被打印出来了。
  • 我想你会找到答案here
  • 我执行的函数是getInstalledPackages from github.com/vle-forge/pyvle/blob/master/src/pyvle.py
  • @andi 这就是我的怀疑。如果你写一个答案,我会接受它。
  • 我会这样做的。给我一分钟。

标签: python process multiprocessing fork python-multiprocessing


【解决方案1】:

您正在寻找的答案详细地址为here。还有一个解释不同操作系统之间的差异。

一个大问题是fork 系统调用在Windows 上不存在。因此,在运行 Windows 操作系统时,您不能使用此方法。 multiprocessing 是执行当前运行程序的一部分的更高级别的接口。因此,它 - 就像分叉一样 - 创建您的流程当前状态的副本。也就是说,它会为您处理程序的分叉。

因此,如果可用,您可以考虑将fork() 视为派生程序的低级接口,而将multiprocessing 库视为派生的高级接口。

【讨论】:

  • 拜托,如果其他人与上面的用户有相同的问题,这个答案除了另一个链接之外没有提供任何东西。如果您可以按照社区指南的要求将相关信息放入您的答案中,我将删除我的反对票。
  • 我希望这是您所要求的。否则让我知道。感谢您的批评。
  • 它实际上不会在 Windows 中创建当前进程的副本。否则,here 列出的所有警告都不是问题。详情请参阅我的回答。
  • '为你处理分叉' ...如果我的程序在锁内分叉怎么办。预期会出现死锁吗?如果我和分叉之间有一层抽象,那么细节很重要。
【解决方案2】:

要直接回答您的问题,external_process 一定有一些副作用,因此当代码串联运行时,您会得到与同时运行它们不同的结果。这是由于您设置代码的方式,以及在支持os.fork 的系统中os.forkmultiprocessing.Process 之间没有区别。


os.forkmultiprocessing.Process 之间唯一真正的区别是可移植性和库开销,因为 Windows 不支持 os.fork,并且包含 multiprocessing 框架以使 multiprocessing.Process 工作。这是因为os.forkmultiprocessing.Process 调用,作为this answer 备份。

因此,重要的区别是os.fork 使用 Unix 的分叉复制当前进程中的所有内容,这意味着在分叉时两个进程相同,但 PID 不同。在 Window 中,这是通过重新运行 if __name__ == '__main__': 之前的所有设置代码来模拟的,这与使用 subprocess 库创建子进程大致相同。

对你来说,你提供的代码 sn-ps 在上面做着完全不同的事情,因为你在第二个代码片段中打开新进程之前在 main 中调用了external_function,这使得这两个进程串联运行但不同过程。管道也是不必要的,因为它没有模拟第一个代码中的任何功能。

在 Unix 中,代码 sn-ps:

import os

pid = os.fork()

if pid == 0:
    os.environ['HOME'] = "rep1"
    external_function()
else:
    os.environ['HOME'] = "rep2"
    external_function()

和:

import os
from multiprocessing import Process

def f():
    os.environ['HOME'] = "rep1"
    external_function()

if __name__ == '__main__':
    p = Process(target=f)
    p.start()
    os.environ['HOME'] = "rep2"
    external_function()
    p.join()

应该做完全一样的事情,但是从包含的多处理库中获得一点额外的开销。


没有更多信息,我们无法弄清楚问题所在。如果您可以提供演示该问题的代码,那将有助于我们为您提供帮助。

【讨论】:

  • Dano的例子和我的函数做的不一样
  • 但他的评论仍然有效,如果没有您的意见,我们无法重现您遇到的行为。
  • 如果你想重现我遇到的行为,你必须安装一堆包。
  • 如果 Dano 的编辑是正确的,那么我们无法在不知道包名称的情况下回答您的问题。
  • 如果你知道它们之间的区别,你可以回答我。
猜你喜欢
  • 2020-03-14
  • 2011-11-04
  • 2017-10-09
  • 2011-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多