python子进程关闭fd_如果创建了multiprocessing.Pool,Python子进程wait()将失败

在一个使用subprocess到gzip输出的简单脚本中(使用subprocess.PIPE到外部命令的stdin),如果在创建子进程和关闭进程的stdin之间创建了multiprocessing.Pool对象,则subprocess.wait ()将永远挂起.

import multiprocessing

import subprocess

proc = subprocess.Popen(["gzip", "-c", "-"],

stdout=open('filename', 'w'), stdin=subprocess.PIPE)

multiprocessing.Pool()

proc.stdin.close()

proc.wait()

移动multiprocessing.Pool调用一行或一行调用可以防止出现问题.

我在Python 2.7.3(Linux)和Python 2.7.1(OS X)上遇到过这种情况.

显然,这是一个微不足道的例子 – 真正的用法要复杂得多.我也已经知道GzipFile了 – 我宁愿不使用它;使用子进程可以通过将gzipping分成单独的线程来获得更多的CPU使用率.

我看不出简单地实例化Pool应该如何产生这种影响.

最佳答案 当您调用multiprocessing.Pool时,多处理模块会创建几个新进程(使用os.fork或类似的进程).

默认情况下,在fork期间,新进程会继承所有打开的文件描述符.

当您使用subprocess.PIPE参数调用subprocess.Popen时,子流程模块会创建一些新的管道文件描述符,以便向/从新进程发送数据.在这种特殊情况下,管道用于将数据从父进程(python)发送到子进程(gzip),并且gzip将退出 – 从而使proc.wait()完成 – 当对管道的所有写访问权限进行时远. (这是在管道上生成“EOF”的原因:该管道不再存在可写入的文件描述符.)

因此,在这种情况下,如果您(所有在“原始”python进程中)按此顺序执行此操作:

>创建一个管道

>创建一些multiprocessing.Pool流程

>将数据发送到gzip

>关闭管道以gzip

然后,由于fork的行为,每个Pool进程都有一个写入gzip管道的os.dup,因此gzip继续等待更多数据,这些池进程可以(但从不这样做)发送.一旦Pool进程关闭其管道描述符,gzip进程就会退出.

将其修复为真实(更复杂)的代码可能非常重要.理想情况下,您希望多处理.Pool(知道,不知何故)应该保留哪些文件描述符,哪些不应该保留,但这并不像“只是在创建的子进程中关闭一堆描述符”那么简单:

output = open('somefile', 'a')

def somefunc(arg):

... do some computation, etc ...

output.write(result)

pool = multiprocessing.Pool()

pool.map(somefunc, iterable)

显然,output.fileno()必须由工作进程共享.

您可以尝试使用Pool的初始化程序来调用proc.stdin.close(或在fd列表中的os.close),但是您需要安排跟踪描述符到关闭.重构代码可能最简单,以避免“在错误的时间”创建池.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值