os.fork和multiprocessing.Process的行为区别
我有这段代码:
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
中的目录被创建。
为什么第二个例子没有在rep1
和rep2
中都创建目录呢?
2 个回答
直接回答你的问题,external_process
可能有一些副作用,这导致当你按顺序运行代码时,得到的结果和同时运行时不同。这是因为你设置代码的方式,以及在支持 os.fork
的系统中,os.fork
和 multiprocessing.Process
之间没有太大区别。
其实,os.fork
和 multiprocessing.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 库的开销。
没有更多的信息,我们无法找出问题所在。如果你能提供演示问题的代码,那将有助于我们帮助你。
你想要的答案在这里有详细的说明,点击这里可以查看。里面还解释了不同操作系统之间的差异。
一个大问题是,fork
这个系统调用在Windows上是不存在的。因此,如果你在使用Windows操作系统,就不能用这种方法。multiprocessing
是一个更高级的接口,用来执行当前程序的一部分。也就是说,它会像fork
那样,创建你程序当前状态的一个副本。换句话说,它为你处理了程序的分叉。
所以,如果有的话,你可以把fork()
看作是一个更底层的程序分叉接口,而multiprocessing
库则是一个更高级的分叉接口。