簡體   English   中英

為什么在通信()完成后子進程繼續運行?

[英]Why does subprocess keep running after communicate() is finished?

我有一個較舊的 python 2.7.5 腳本,它突然在 Red Hat Enterprise Linux 服務器版本 7.6 (Maipo) 上出現問題。 畢竟我看到,它在 Red Hat Enterprise Linux 服務器版本 7.4 (Maipo) 上運行良好。 該腳本基本上實現了類似

cat /proc/cpuinfo | grep -m 1 -i 'cpu MHz'

通過創建兩個子進程並將第一個的 output 輸送到第二個(參見下面的代碼示例)。 在較新的操作系統版本上,cat 進程保持打開狀態,直到腳本終止。

看來,pipe 到 grep 以某種方式保持 cat 進程打開,我找不到任何關於如何明確關閉它的文檔。

通過將此代碼粘貼到 python CLI 然后檢查 ps 進程列表中的 static 進程“cat /proc/cpuinfo”,可以重現該問題。 該代碼正在分解循環內最初發生的事情,所以請不要爭論它的風格。 ;-)

import shlex
from subprocess import *
cmd1 = "cat /proc/cpuinfo"
cmd2 = "grep -m 1 -i 'cpu MHz'"
args1 = shlex.split(cmd1) # split into args
args2 = shlex.split(cmd2) # split into args
# first process uses default stdin
ps1 = Popen(args1, stdout=PIPE)
# then use the output of the previous process as stdin
ps2 = Popen(args2, stdin=ps1.stdout, stdout=PIPE)
out, err = ps2.communicate()
print(out)

然后在第二個會話(:) 中檢查進程列表:

ps -eF |grep -v grep|grep /proc/cpuinfo

在 RHEL7.4 上,我在進程列表中找不到打開的進程,而在 RHEL 7.6 上經過一些嘗試后,它看起來像這樣:

[reinski@myhost ~]$ ps -eF |grep -v grep|grep /proc/cpuinfo
reinski    2422  89459  0 26993   356 142 18:46 pts/3    00:00:00 cat /proc/cpuinfo
reinski    2597 139605  0 26993   352  31 18:39 pts/3    00:00:00 cat /proc/cpuinfo
reinski    7809 139605  0 26993   352  86 18:03 pts/3    00:00:00 cat /proc/cpuinfo

只有當我關閉 python CLI 時,這些進程才會消失,在這種情況下,我會收到這樣的錯誤(我把格式弄亂了):

cat: write error: Broken pipe
cat: write errorcat: write error: Broken pipe
: Broken pipe

為什么 cat 顯然仍然想寫入 pipe,即使它應該已經 output 整個 /proc/cpuinfo 並且應該已經終止了自己?

或更重要的是:我怎樣才能防止這種情況發生?

謝謝你的幫助!

示例 2:

事實證明,鑒於 VPfB 的建議,我的示例有點不走運,因為可以通過單個 grep 命令實現預期結果。 因此,這里有一個修改后的示例,以另一種方式顯示管道問題:

import shlex
from subprocess import *
cmd1 = "grep -m 1 -i 'cpu MHz' /proc/cpuinfo"
cmd2 = "awk '{print $4}'"
args1 = shlex.split(cmd1) # split into args
args2 = shlex.split(cmd2) # split into args
# first process uses default stdin
ps1 = Popen(args1, stdout=PIPE)
# then use the output of the previous process as stdin
ps2 = Popen(args2, stdin=ps1.stdout, stdout=PIPE)
out, err = ps2.communicate()
print(out)

這一次,結果是 grep 進程的單個僵屍進程(169731 是 python 會話的 pid):

[reinski@myhost ~]$ ps -eF|grep 169731
reinski  169731 189499  0 37847  6024 198 17:51 pts/2    00:00:00 python
reinski  193999 169731  0     0     0 142 17:53 pts/2    00:00:00 [grep] <defunct>

那么,這只是同一問題的另一個症狀,還是我在這里做錯了什么?

好的,看來我剛剛從示例中找到了一個讓僵屍進程保持打開狀態的解決方案:只需要做一個

ps1.communicate()

看來,這是正確關閉 pipe 所必需的。 我希望在調用第二個進程的通信()並從第一個進程讀取 pipe 時會發生這種情況。

有人可以向我指出,我在這里缺少什么嗎? 我總是願意學習... ;-)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM