多处理和全局文件句柄的奇怪行为

时间:2017-06-06 16:47:00

标签: python multiprocessing

有人可以帮助我理解以下代码段吗?我知道我不能使用multiprocessing使用全局变量,但我仍然对我看到的结果感到惊讶。

我在另一个工作进程中远程执行的函数中使用了一个全局文件句柄。

import multiprocessing
import os

fh = open("out.txt", "w")

def process(i):
    print("i={}  pid={}  id(fh)={}".format(i, os.getpid(), id(fh)))
    print(i, file=fh)

def main():
    p = multiprocessing.Pool(3)
    p.map(process, (1, 2, 3))
    p.terminate()
    fh.close()

main()

输出

i=1  pid=92045  id(fh)=4314964256
i=2  pid=92046  id(fh)=4314964256
i=3  pid=92047  id(fh)=4314964256

因此我们看到有三种不同的流程ID正如预期的那样。

让我大吃一惊的是:

  1. 工作进程中提供了不可删除的文件句柄
  2. id计算的内存地址对于所有工作人员都是相同的
  3. 工作进程可以写入此文件句柄而不会抛出异常
  4. 然而,程序执行后文件为空。

1 个答案:

答案 0 :(得分:1)

自己找到答案:

  1. 工作进程中提供了不可删除的文件句柄:来自Python解释器进程的multiprocessing分叉,因此全局变量被复制到内存中(SO multiprocessing global variable memory copying)。在子解释器中调用函数时,只会对函数参数进行酸洗。
  2. 由id计算的内存地址对于所有工作人员都是相同的:显示的内存地址是虚拟地址空间中因此相对的地址。分叉后,初始内存布局是相同的。 (SO post Fork - same memory addresses?
  3. 工作进程可以写入此文件句柄而不会抛出异常:请参阅答案1 + 对于分叉进程,fileno的基础fh是相同的。
  4. 然而,程序执行后文件为空:如果在从flush返回之前调用process方法,则文件不为空。因此,当进程被其父进程终止时,文件缓冲区不会被刷新。
  5. 注: 我的示例应该在Windows上表现不同。由于不同的流程模型/实现,Windows上的multiprocessing必须启动新的Python解释器。