如果没有在一小时内结束,请运行一个进程并将其终止
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如果没有在一小时内结束,请运行一个进程并将其终止相关的知识,希望对你有一定的参考价值。
我需要在Python中执行以下操作。我想生成一个进程(子进程模块?),并且:
- 如果过程正常结束,从它终止的那一刻起就完全继续;
- 如果,否则,进程“卡住”并且不会在(例如)一小时内终止,以杀死它并继续(可能在循环中再次尝试)。
实现这一目标的最优雅方式是什么?
subprocess
模块将成为你的朋友。启动进程以获取Popen
对象,然后将其传递给这样的函数。请注意,这仅在超时时引发异常。如果需要,您可以捕获异常并在kill()
进程上调用Popen
方法。 (杀死是Python 2.6中的新功能,顺便说一句)
import time
def wait_timeout(proc, seconds):
"""Wait for a process to finish, or raise exception after timeout"""
start = time.time()
end = start + seconds
interval = min(seconds / 1000.0, .25)
while True:
result = proc.poll()
if result is not None:
return result
if time.time() >= end:
raise RuntimeError("Process timed out")
time.sleep(interval)
只要您知道进程PID,使用psutil至少有两种方法可以做到这一点。假设该过程是这样创建的:
import subprocess
subp = subprocess.Popen(['progname'])
...你可以在这样一个繁忙的循环中获得它的创建时间:
import psutil, time
TIMEOUT = 60 * 60 # 1 hour
p = psutil.Process(subp.pid)
while 1:
if (time.time() - p.create_time) > TIMEOUT:
p.kill()
raise RuntimeError('timeout')
time.sleep(5)
......或者简单地说,你可以这样做:
import psutil
p = psutil.Process(subp.pid)
try
p.wait(timeout=60*60)
except psutil.TimeoutExpired:
p.kill()
raise
此外,当您遇到它时,您可能会对以下额外的API感兴趣:
>>> p.status()
'running'
>>> p.is_running()
True
>>>
我有一个类似的问题,并找到了这个答案。为了完整起见,我想再添加一个如何在给定时间后终止挂起进程的方法:python信号库https://docs.python.org/2/library/signal.html
从文档:
import signal, os
def handler(signum, frame):
print 'Signal handler called with signal', signum
raise IOError("Couldn't open device!")
# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)
signal.alarm(0) # Disable the alarm
既然你想要生成一个新的进程,那么这可能不是你问题的最佳解决方案。
一个好的,被动的方式也是使用threading.Timer和设置回调函数。
from threading import Timer
# execute the command
p = subprocess.Popen(command)
# save the proc object - either if you make this onto class (like the example), or 'p' can be global
self.p == p
# config and init timer
# kill_proc is a callback function which can also be added onto class or simply a global
t = Timer(seconds, self.kill_proc)
# start timer
t.start()
# wait for the test process to return
rcode = p.wait()
t.cancel()
如果进程及时完成,则wait()结束并且代码在此处继续,cancel()将停止计时器。如果同时计时器用完并在一个单独的线程中执行kill_proc,那么wait()也将在此处继续,cancel()将不执行任何操作。通过rcode的值,您将知道我们是否已经超时。最简单的kill_proc :(你当然可以做额外的事情)
def kill_proc(self):
os.kill(self.p, signal.SIGTERM)
Koodos向Peter Shinners提出了关于subprocess
模块的好建议。我之前使用过exec()
并且没有任何控制运行时间,特别是终止它。我这种任务最简单的模板如下,我只是使用subprocess.run()
函数的timeout参数来监控运行时间。当然,如果需要,您也可以获得标准输出和错误:
from subprocess import run, TimeoutExpired, CalledProcessError
for file in fls:
try:
run(["python3.7", file], check=True, timeout=7200) # 2 hours timeout
print("scraped :)", file)
except TimeoutExpired:
message = "Timeout :( !!!"
print(message, file)
f.write("message file\n".format(file=file, message=message))
except CalledProcessError:
message = "SOMETHING HAPPENED :( !!!, CHECK"
print(message, file)
f.write("message file\n".format(file=file, message=message))
以上是关于如果没有在一小时内结束,请运行一个进程并将其终止的主要内容,如果未能解决你的问题,请参考以下文章