Python子进程杀死超时
我正在python中使用subprocess模块运行一些shell脚本。如果shell脚本运行时间很长,我想杀死该子进程。我认为如果将其传递timeout=30
给我的run(..)
陈述就足够了。
这是代码:
try:
result=run(['utilities/shell_scripts/{0} {1} {2}'.format(
self.language_conf[key][1], self.proc_dir, config.main_file)],
shell=True,
check=True,
stdout=PIPE,
stderr=PIPE,
universal_newlines=True,
timeout=30,
bufsize=100)
except TimeoutExpired as timeout:
我已经用一些运行120秒的shell脚本测试了此调用。我期望子进程在30秒后被杀死,但是实际上该进程正在完成120秒脚本,然后引发了Timeout
Exception。现在的问题是如何通过超时杀死子进程?
-
该文档明确指出应终止该进程:
“
timeout参数传递给Popen.communicate()。如果超时到期,子进程将被杀死并等待。子进程终止后,将重新引发TimeoutExpired异常。”但是在您的情况下,您正在使用
shell=True
,而且我之前也遇到过类似的问题,因为阻塞过程是Shell过程的子过程。我认为,
shell=True
如果适当地分解参数并且脚本具有适当的shebang,则不需要。您可以尝试以下方法:result=run( [os.path.join('utilities/shell_scripts',self.language_conf[key][1]), self.proc_dir, config.main_file], # don't compose argument line yourself shell=False, # no shell wrapper check=True, stdout=PIPE, stderr=PIPE, universal_newlines=True, timeout=30, bufsize=100)
请注意,我可以在Windows上非常轻松地重现此问题(使用
Popen
,但这是同一回事):import subprocess,time p=subprocess.Popen("notepad",shell=True) time.sleep(1) p.kill()
=>记事本保持打开状态,可能是因为它设法脱离了父shell进程。
import subprocess,time p=subprocess.Popen("notepad",shell=False) time.sleep(1) p.kill()
=>记事本在1秒后关闭
有趣的是,如果将其删除
time.sleep()
,kill()
即使shell=True
可能成功杀死正在启动的外壳,它也可以正常工作notepad
。我并不是说您有完全相同的问题,我只是
shell=True
出于多种原因证明这是邪恶的,而无法中止/超时则是另一个原因。但是, 如果
你需要shell=True
一个理由,你可以使用psutil
杀到底所有的孩子。在这种情况下,最好使用它,Popen
以便直接获取进程ID:import subprocess,time,psutil parent=subprocess.Popen("notepad",shell=True) for _ in range(30): # 30 seconds if parent.poll() is not None: # process just ended break time.sleep(1) else: # the for loop ended without break: timeout parent = psutil.Process(parent.pid) for child in parent.children(recursive=True): # or parent.children() for recursive=False child.kill() parent.kill()
(资料来源:如何从python中杀死进程和子进程?)
该示例也会杀死记事本实例。