我对Python的问题(3.4)subprocess.popen
:
很少(曾经有几千个),对popen
的调用似乎创建了另一个分叉进程,除了故意进程和挂起(可能等待?),导致故意进程变成僵尸。
这是呼叫顺序:
with subprocess.Popen(['prog', 'arg1', 'arg2'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
std_out, std_err = p.communicate()
p.wait()
注意:上面的调用序列是从分叉进程本身运行的(进程池的一种形式,请参阅下面的进程列表)
问题发生在多个程序中(例如7z)所以我认为问题出在调用者而不是被调用者。
prog
是zombiefied,因此我假设p.wait()
语句从未到达或未正确执行。
生成的进程列表(ps -ef输出):
my_user 18219 18212 9 16:16 pts/1 00:18:11 python3 script.py # original process
my_user 1045 18219 0 16:18 pts/1 00:00:14 python3 script.py # Intentionally forked from original (poor man's process pool) - Seems to be stuck or waiting
my_user 2834 1045 0 16:18 pts/1 00:00:00 [prog] <defunct> # Program run by subprocess.popen - Zombie
my_user 2841 1045 0 16:18 pts/1 00:00:00 python3 script.py # !!!! Should not be here, also stuck or waiting, never finishes
已编辑(根据要求添加了代码示例): 问题中的代码:
import os
import subprocess
pid = os.fork()
if pid == 0:
# child
file_name='test.zip'
out_dir='/tmp'
while True:
with subprocess.Popen(['7z', 'x', '-y', '-p', '-o' + out_dir, file_name], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) as p:
try:
std_out, std_err = p.communicate(timeout=600)
except subprocess.TimeoutExpired:
p.kill()
std_out, std_err = p.communicate()
logging.critical('7z failed, a timeout has occurred during waiting')
except:
p.kill()
p.wait()
raise
return_code = p.poll()
# do something
else:
# parent
wpid, status = os.waitpid(pid, 0)
exit_code = status >> 8
答案 0 :(得分:1)
subprocess
确实在运行命令之前分叉。这在PEP 324中提到(ctrl-f代表“fork”)。
原因是命令是使用exec
运行的,替换执行的调用进程。
正如您所看到的,它与执行的脚本共享相同的pid,因此它实际上是相同的进程,但它不是正在运行的python解释器。
因此,只要子进程没有返回,调用者python进程就不能。
答案 1 :(得分:0)
我认为这是混合分叉和线程的效果,这在Linux中是一件坏事。以下是几个参考文献:
导入logging
模块后,我相信您的流程是多线程的。 (在我的情况下,我有时看到我的程序在等待logging
futex时挂起,有时在subprocess
内等待,而子进程已成为僵尸时挂起。)该模块使用OS锁来确保它可以以线程安全的方式调用。一旦fork,该锁的状态将由子进程继承。因此,子进程(单线程但继承了父进程的内存)无法获取logging
锁,因为在发生fork时锁有时会被锁定。
(我对我的解释并不十分自信。当我从使用multiprocessing
的默认fork行为切换到使用spawn行为时,我的问题就消失了。在后者中,一个孩子没有继承其父亲的记忆,subprocess
和logging
不再对我造成影响。)