为什么communication()完​​成后子进程仍继续运行?

时间:2019-10-21 16:57:18

标签: python subprocess pipe

我有一个较旧的python 2.7.5脚本,该脚本在Red Hat Enterprise Linux Server 7.6(Maipo)上突然出现问题。毕竟,它在Red Hat Enterprise Linux Server 7.4版(Maipo)上运行良好。 该脚本基本上实现了

之类的东西

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

通过创建两个子过程并将第一个子过程的输出传递到第二个子过程(请参见下面的代码示例)来

。在较新的OS版本上,cat进程保持打开状态,直到脚本终止。

似乎grep的管道以某种方式使cat进程保持打开状态,而我找不到任何有关如何明确关闭它的文档。

可以通过将此代码粘贴到python CLI中,然后检查ps进程列表中的静态进程'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尽管它应该已经输出了完整的/ 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>

那么,这仅仅是同一问题的另一种症状,还是我在这里做错了什么?

1 个答案:

答案 0 :(得分:0)

好吧,看来我只是从示例中找到了一个僵尸进程解决方案的解决方案: 只需要做一个

ps1.communicate()

看来,这是正确关闭管道所必需的。 我希望在第二个进程的communication()被调用并从第一个进程读取管道时会发生这种情况。

有人可以指出我,我在这里想念的是什么吗? 我一直乐于学习...;-)