gpt4 book ai didi

Python 子进程超时终止

转载 作者:行者123 更新时间:2023-11-28 22:20:43 25 4
gpt4 key购买 nike

我正在使用 python 中的子进程模块运行一些 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 秒的脚本,然后引发超时异常。现在的问题是如何通过超时终止子进程?

最佳答案

文档明确指出应该终止该进程:

来自 docs for subprocess.run :

"The timeout argument is passed to Popen.communicate(). If the timeout expires, the child process will be killed and waited for. The TimeoutExpired exception will be re-raised after the child process has terminated."

但在您的情况下,您使用的是 shell=True,而且我以前见过类似的问题,因为阻塞进程是 shell 进程的子进程。

如果您正确分解参数并且您的脚本具有适当的 shebang,我认为您不需要 shell=True。你可以试试这个:

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。

我并不是说您有完全相同的问题,我只是在证明 shell=True 出于多种原因是邪恶的,无法终止/超时进程是另一个原因原因。

但是,如果您出于某种原因需要 shell=True,您可以使用 psutil 最后杀死所有的 child 。在这种情况下,最好使用 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()

(来源:how to kill process and child processes from python?)

那个例子也杀死了记事本实例。

关于Python 子进程超时终止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48763362/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com