Python 超时时终止或终止子进程?
我希望尽可能快地重复执行子流程。然而,有时这个过程会花太长时间,所以我想杀死它。 我使用信号。信号(…)如下所示:Python 超时时终止或终止子进程?,python,timeout,subprocess,kill,signals,Python,Timeout,Subprocess,Kill,Signals,我希望尽可能快地重复执行子流程。然而,有时这个过程会花太长时间,所以我想杀死它。 我使用信号。信号(…)如下所示: ppid=pipeexe.pid signal.signal(signal.SIGALRM, stop_handler) signal.alarm(1) ..... def stop_handler(signal, frame): print 'Stop test'+testdir+'for time out' if(pipeexe.poll()==None an
ppid=pipeexe.pid
signal.signal(signal.SIGALRM, stop_handler)
signal.alarm(1)
.....
def stop_handler(signal, frame):
print 'Stop test'+testdir+'for time out'
if(pipeexe.poll()==None and hasattr(signal, "SIGKILL")):
os.kill(ppid, signal.SIGKILL)
return False
但有时,这段代码会试图阻止下一轮的执行。
暂停测试/home/lu/workspace/152/treefit/test2以等待超时
/bin/sh:/home/lu/workspace/153/squib_驱动程序:未找到---这是下一次执行;程序错误地停止了它
有人知道如何解决这个问题吗?我想及时停止,而不是执行1秒的时间。睡眠(n)通常等待n秒。我不希望它能在1秒之内执行,我想这是线程和进程面向事件编程中常见的同步问题 如果始终只运行一个子流程,请确保在运行下一个子流程之前先终止当前子流程。否则,信号处理程序可能会获取对上一个子流程运行的引用,并忽略较旧的子流程 假设子进程A正在运行。在处理报警信号之前,启动子流程B。在此之后,报警信号处理程序将尝试终止子进程。当启动子流程时,当前PID(或当前子流程管道对象)设置为B时,B被终止,A继续运行 我的猜测正确吗
为了使您的代码更容易理解,我将包括在终止当前子流程的部分之后创建新子流程的部分。这将清楚地表明,任何时候都只有一个子流程在运行。信号处理程序可以同时执行子流程终止和启动,就像循环中运行的迭代块一样,在这种情况下,每1秒用报警信号驱动一次事件。您可以执行以下操作:
import subprocess as sub
import threading
class RunCmd(threading.Thread):
def __init__(self, cmd, timeout):
threading.Thread.__init__(self)
self.cmd = cmd
self.timeout = timeout
def run(self):
self.p = sub.Popen(self.cmd)
self.p.wait()
def Run(self):
self.start()
self.join(self.timeout)
if self.is_alive():
self.p.terminate() #use self.p.kill() if process needs a kill -9
self.join()
RunCmd(["./someProg", "arg1"], 60).Run()
其思想是创建一个线程来运行该命令,并在超时超过某个合适的值(在本例中为60秒)时终止该命令。以下是我作为子流程执行的看门狗编写的内容。我现在经常使用它,但我没有那么多经验,所以可能有一些缺陷:
import subprocess
import time
def subprocess_execute(command, time_out=60):
"""executing the command with a watchdog"""
# launching the command
c = subprocess.Popen(command)
# now waiting for the command to complete
t = 0
while t < time_out and c.poll() is None:
time.sleep(1) # (comment 1)
t += 1
# there are two possibilities for the while to have stopped:
if c.poll() is None:
# in the case the process did not complete, we kill it
c.terminate()
# and fill the return code with some error value
returncode = -1 # (comment 2)
else:
# in the case the process completed normally
returncode = c.poll()
return returncode
评论:
time.sleep()
值,可以很容易地更改为所需的任何内容。必须相应地记录超时
李>
子流程
模块的文档做了一些努力,以理解子流程.Popen
没有阻塞;这个过程是并行执行的(也许我在这里没有使用正确的词,但我认为这是可以理解的)
但是,由于我编写的脚本在执行过程中是线性的,因此我必须等待命令完成,并留出一段时间,以避免命令中出现错误,从而暂停脚本的夜间执行。以下是我使用的方法:
class KillerThread(threading.Thread):
def __init__(self, pid, timeout, event ):
threading.Thread.__init__(self)
self.pid = pid
self.timeout = timeout
self.event = event
self.setDaemon(True)
def run(self):
self.event.wait(self.timeout)
if not self.event.isSet() :
try:
os.kill( self.pid, signal.SIGKILL )
except OSError, e:
#This is raised if the process has already completed
pass
def runTimed(dt, dir, args, kwargs ):
event = threading.Event()
cwd = os.getcwd()
os.chdir(dir)
proc = subprocess.Popen(args, **kwargs )
os.chdir(cwd)
killer = KillerThread(proc.pid, dt, event)
killer.start()
(stdout, stderr) = proc.communicate()
event.set()
return (stdout,stderr, proc.returncode)
更为复杂的是,我添加了一个:捕获stdout,输入stdin,并能够在一段时间的不活动和/或某个总体运行时间后终止。因此,如果子进程运行超过1秒,基本上你想杀死它并启动下一个吗?这是否正确?如何创建子流程?因为它看起来像表达式ppid=pipeexe.pid正在获取下一个将要运行的子进程!!!因此,如果子进程运行超过1秒,您想终止它并启动下一个进程吗?这是正确的吗?是的,没错。您如何创建子流程?pipeexe=subprocess.Popen(…),因为它看起来像表达式ppid=pipeexe.pid正在获取下一个将要运行的子进程!!我想你可能是对的。但是如何确保下次运行+1时pid不会改变。这个方法就是我在构建系统中用来测试可执行文件的方法。这似乎是迄今为止我见过的最干净的方法之一。只需稍加修改,就可以在linux上使用os.kill(self.p.pid,signal.SIGKILL)(或SIGTERM后跟SIGKILL)在Python<2.6上工作。还可以将self.p.wait()替换为self.out,self.err=self.p.communicate(),以避免在子进程填满stdout/stderr管道时阻塞子进程。我粘贴了此代码,并且我的命令似乎启动正常-但是,我需要一次运行一个线程。启动一个进程,让它自然完成,或者如果需要的时间太长,则终止它,然后重新启动。是否可以从中获取Popen的返回值?@galois:
Run()
方法执行self.Start()
语句后,RunCmd
实例的self.p
包含已创建的子流程.Popen
实例,因此您可以通过这种方式访问它。你为什么要这个?
class KillerThread(threading.Thread):
def __init__(self, pid, timeout, event ):
threading.Thread.__init__(self)
self.pid = pid
self.timeout = timeout
self.event = event
self.setDaemon(True)
def run(self):
self.event.wait(self.timeout)
if not self.event.isSet() :
try:
os.kill( self.pid, signal.SIGKILL )
except OSError, e:
#This is raised if the process has already completed
pass
def runTimed(dt, dir, args, kwargs ):
event = threading.Event()
cwd = os.getcwd()
os.chdir(dir)
proc = subprocess.Popen(args, **kwargs )
os.chdir(cwd)
killer = KillerThread(proc.pid, dt, event)
killer.start()
(stdout, stderr) = proc.communicate()
event.set()
return (stdout,stderr, proc.returncode)