os.fork和multiprocessing.Process的行为区别

11 投票
2 回答
17470 浏览
提问于 2025-04-18 08:36

我有这段代码:

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中都创建目录呢?

2 个回答

4

直接回答你的问题,external_process 可能有一些副作用,这导致当你按顺序运行代码时,得到的结果和同时运行时不同。这是因为你设置代码的方式,以及在支持 os.fork 的系统中,os.forkmultiprocessing.Process 之间没有太大区别。


其实,os.forkmultiprocessing.Process 之间唯一真正的区别是可移植性和库的开销,因为 os.fork 在 Windows 上不支持,而 multiprocessing 框架是为了让 multiprocessing.Process 能够工作而包含的。这是因为 os.fork 是由 multiprocessing.Process 调用的,正如这个回答所支持的。

那么,重要的区别在于 os.fork 使用 Unix 的分叉机制复制当前进程中的所有内容,这意味着在分叉时,两个进程是相同的,只是进程ID不同。在 Windows 中,这通过在 if __name__ == '__main__': 之前重新运行所有设置代码来模拟,这大致上和使用 subprocess 库创建子进程是一样的。

对你来说,你提供的代码片段在上面做的事情是相当不同的,因为你在打开新进程之前在主程序中调用了 external_function,这使得两个进程是顺序运行但在不同的进程中。此外,管道是没有必要的,因为它没有模拟第一个代码的任何功能。

在 Unix 中,这些代码片段:

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()

应该做完全相同的事情,只是多了一些来自于包含的 multiprocessing 库的开销。


没有更多的信息,我们无法找出问题所在。如果你能提供演示问题的代码,那将有助于我们帮助你。

15

你想要的答案在这里有详细的说明,点击这里可以查看。里面还解释了不同操作系统之间的差异。

一个大问题是,fork这个系统调用在Windows上是不存在的。因此,如果你在使用Windows操作系统,就不能用这种方法。multiprocessing是一个更高级的接口,用来执行当前程序的一部分。也就是说,它会像fork那样,创建你程序当前状态的一个副本。换句话说,它为你处理了程序的分叉。

所以,如果有的话,你可以把fork()看作是一个更底层的程序分叉接口,而multiprocessing库则是一个更高级的分叉接口。

撰写回答