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),但是您需要安排跟蹤描述符到關閉.重構代碼可能最簡單,以避免“在錯誤的時間”創建池.
總結
以上是生活随笔為你收集整理的python子进程关闭fd_如果创建了multiprocessing.Pool,Python子进程wait()将失败的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python合并excel文件关键字_p
- 下一篇: python红包游戏_脑力2048红包版