Python 超时时终止或终止子进程?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4158502/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Kill or terminate subprocess when timeout?
提问by user504909
I would like to repeatedly execute a subprocess as fast as possible. However, sometimes the process will take too long, so I want to kill it. I use signal.signal(...) like below:
我想尽可能快地重复执行一个子流程。但是,有时这个过程会花费太长时间,所以我想杀死它。我使用 signal.signal(...) 如下所示:
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
but sometime this code will try to stop the next round from executing. Stop test/home/lu/workspace/152/treefit/test2for time out /bin/sh: /home/lu/workspace/153/squib_driver: not found ---this is the next execution; the program wrongly stops it.
但有时这段代码会试图阻止下一轮的执行。停止 test/home/lu/workspace/152/treefit/test2 for timeout /bin/sh: /home/lu/workspace/153/squib_driver: not found ---这是下一次执行;程序错误地停止了它。
Does anyone know how to solve this? I want to stop in time not execute 1 second the time.sleep(n) often wait n seconds. I do not want that I want it can execute less than 1 second
有谁知道如何解决这个问题?我想及时停止不执行 1 秒 time.sleep(n) 经常等待 n 秒。我不希望我希望它可以执行不到 1 秒
采纳答案by ralphtheninja
You could do something like this:
你可以这样做:
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()
The idea is that you create a thread that runs the command and to kill it if the timeout exceeds some suitable value, in this case 60 seconds.
这个想法是你创建一个线程来运行命令并在超时超过某个合适的值时终止它,在这种情况下是 60 秒。
回答by scoffey
I guess this is a common synchronization problem in event-oriented programming with threads and processes.
我猜这是线程和进程的面向事件编程中常见的同步问题。
If you should always have only one subprocess running, make sure the current subprocess is killed before running the next one. Otherwise the signal handler may get a reference to the last subprocess run and ignore the older.
如果您应该始终只运行一个子进程,请确保在运行下一个子进程之前终止当前子进程。否则信号处理程序可能会获得对最后一个子进程运行的引用并忽略旧的。
Suppose subprocess A is running. Before the alarm signal is handled, subprocess B is launched. Just after that, your alarm signal handler attempts to kill a subprocess. As the current PID (or the current subprocess pipe object) was set to B's when launching the subprocess, B gets killed and A keeps running.
假设子进程 A 正在运行。在处理报警信号之前,启动子进程 B。在那之后,您的警报信号处理程序尝试终止子进程。由于当前 PID(或当前子进程管道对象)在启动子进程时设置为 B,因此 B 被杀死,而 A 继续运行。
Is my guess correct?
我的猜测正确吗?
To make your code easier to understand, I would include the part that creates a new subprocess just after the part that kills the current subprocess. That would make clear there is only one subprocess running at any time. The signal handler could do both the subprocess killing and launching, as if it was the iteration block that runs in a loop, in this case event-driven with the alarm signal every 1 second.
为了使您的代码更易于理解,我将在杀死当前子进程的部分之后包含创建新子进程的部分。这将表明在任何时候都只有一个子进程在运行。信号处理程序可以同时执行子进程终止和启动,就好像它是在循环中运行的迭代块,在这种情况下,每 1 秒由事件驱动并带有警报信号。
回答by Jo?l
Here is something I wrote as a watchdog for subprocess execution. I use it now a lot, but I'm not so experienced so maybe there are some flaws in it:
这是我作为子进程执行看门狗编写的内容。我现在经常使用它,但我没有那么有经验,所以也许它有一些缺陷:
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
Usage:
用法:
return = subprocess_execute(['java', '-jar', 'some.jar'])
Comments:
注释:
- here, the watchdog time out is in seconds; but it's easy to change to whatever needed by changing the
time.sleep()value. Thetime_outwill have to be documented accordingly; - according to what is needed, here it maybe more suitable to raise some exception.
- 在这里,看门狗超时以秒为单位;但是通过更改
time.sleep()值可以轻松更改为所需的任何内容。在time_out将要进行相应的记录; - 根据需要,在这里提出一些异常可能更合适。
Documentation: I struggled a bit with the documentation of subprocessmodule to understand that subprocess.Popenis not blocking; the process is executed in parallel (maybe I do not use the correct word here, but I think it's understandable).
文档:我对subprocess模块的文档有点费解,以了解这subprocess.Popen不是阻塞;这个过程是并行执行的(也许我在这里没有使用正确的词,但我认为这是可以理解的)。
But as what I wrote is linear in its execution, I really have to wait for the command to complete, with a time out to avoid bugs in the command to pause the nightly execution of the script.
但是由于我写的在执行中是线性的,我真的必须等待命令完成,并有一个超时以避免命令中的错误暂停脚本的夜间执行。
回答by Michael Anderson
Here's what I use:
这是我使用的:
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)
回答by cfi
A bit more complex, I added an answer to solve a similar problem: Capturing stdout, feeding stdin, and being able to terminate after some time of inactivity and/or after some overall runtime.
稍微复杂一点,我添加了一个解决类似问题的答案:捕获标准输出,提供标准输入,并且能够在一段时间不活动和/或在整个运行时间之后终止。

