2017-04-11 44 views
1

如何设置函数可以运行的最大时间限制? 例如,使用time.sleep作为占位符函数,如何限制时间量time.sleep可以运行最多5分钟(300秒)?如何限制函数可以运行的时间量(添加超时)?

import time 

try: 
    # As noted above `time.sleep` is a placeholder for a function 
    # which takes 10 minutes to complete. 
    time.sleep(600) 
except: 
    print('took too long') 

即,如何能够time.sleep(600)上述限制和300秒后中断?

+0

选项是依赖于平台的。你在哪个平台上? – wim

+0

Ubuntu 16.04 linux – Greg

+0

使用信号。请参阅https://docs.python.org/3/library/signal.html –

回答

3

在POSIX上,您可以在signal模块中获得一个简单而干净的解决方案。

import signal 
import time 

class Timeout(Exception): 
    pass 

def handler(sig, frame): 
    raise Timeout 

signal.signal(signal.SIGALRM, handler) # register interest in SIGALRM events 

signal.alarm(2) # timeout in 2 seconds 
try: 
    time.sleep(60) 
except Timeout: 
    print('took too long') 

注意事项:

  • 不能在所有平台上,例如工作视窗。
  • 不适用于线程应用程序,仅适用于主线程。

对于其他读者,上面的警告是一个交易断路器,你将需要一个更重量级的方法。最好的选择通常是在单独的进程(或可能是一个线程)中运行代码,如果时间过长,则终止该进程。例如,请参阅multiprocessing模块。

+0

底部的示例如果该函数在内部使用多处理,这仍会停止'try'中的函数吗? – Greg

+0

参见注意事项#2。它只在主线程中起作用。 – wim

2

一个目前很可能优先选项来完成你想要的是蟒蛇的使用

多(特别是它的proc.join(timeoutTime)法)

模块(见tutorial

只需复制/粘贴下面的代码示例并运行它。这是你以后的样子吗?

def beBusyFor(noOfSeconds): 
    import time 
    print(" beBusyFor() message: going to rest for", noOfSeconds, "seconds") 
    time.sleep(noOfSeconds) 
    print(" beBusyFor() message: was resting", noOfSeconds, "seconds, now AWAKE") 

import multiprocessing 

noOfSecondsBusy = 5; timeoutTime = 3 
print("--- noOfSecondsBusy = 5; timeoutTime = 3 ---") 
proc = multiprocessing.Process(target=beBusyFor, args=(noOfSecondsBusy,)) 
print("Start beBusyFor()") 
proc.start() 
print("beBusyFor() is running") 
proc.join(timeoutTime) 
if proc.is_alive(): 
    print(timeoutTime, "seconds passed, beBusyFor() still running, terminate()") 
    proc.terminate() 
else: 
    print("OK, beBusyFor() has finished its work in time.") 
#:if  

print() 

noOfSecondsBusy = 2; timeoutTime = 3 
print("--- noOfSecondsBusy = 2; timeoutTime = 3 ---") 
proc = multiprocessing.Process(target=beBusyFor, args=(noOfSecondsBusy,)) 
print("Start beBusyFor()") 
proc.start() 
print("beBusyFor() started") 
proc.join(timeoutTime) 
if proc.is_alive(): 
    print(timeoutTime, "seconds passed, beBusyFor() still running, terminate()") 
    proc.terminate() 
else: 
    print("OK, beBusyFor() has finished its work in time.") 
#:if  

它输出:

--- noOfSecondsBusy = 5; timeoutTime = 3 --- 
Start beBusyFor() 
beBusyFor() is running 
    beBusyFor() message: going to rest for 5 seconds 
3 seconds passed, beBusyFor() still running, terminate() 

--- noOfSecondsBusy = 2; timeoutTime = 3 --- 
Start beBusyFor() 
beBusyFor() started 
    beBusyFor() message: going to rest for 2 seconds 
    beBusyFor() message: was resting 2 seconds, now AWAKE 
OK, beBusyFor() has finished its work in time. 

另一种已知的对我的选择是使用一个

装饰功能信号模块

结帐我在这里提供的web page with origin of the code(只有一个小的调整是必要的,以使其上的Python 3.6运行):

import signal 

class TimeoutError(Exception): 
    def __init__(self, value = "Timed Out"): 
     self.value = value 
    def __str__(self): 
     return repr(self.value) 

def timeout(seconds_before_timeout): 
    def decorate(f): 
     def handler(signum, frame): 
      raise TimeoutError() 
     def new_f(*args, **kwargs): 
      old = signal.signal(signal.SIGALRM, handler) 
      signal.alarm(seconds_before_timeout) 
      try: 
       result = f(*args, **kwargs) 
      finally: 
       signal.signal(signal.SIGALRM, old) 
      signal.alarm(0) 
      return result 
     # new_f.func_name = f.func_name 
     new_f.__name__ = f.__name__ 
     return new_f 
    return decorate 

# Try it out: 

import time 

@timeout(5) 
def mytest(): 
    print("mytest() message: Started") 
    for i in range(1,10): 
     time.sleep(1) 
     print("mytest() message: %d seconds have passed" % i) 

try: 
    mytest() 
except TimeoutError as e: 
    print("stopped executing mytest() because it", e) 

print("continuing script execution past call of mytest()") 

上述输出的代码:

mytest() message: Started 
mytest() message: 1 seconds have passed 
mytest() message: 2 seconds have passed 
mytest() message: 3 seconds have passed 
mytest() message: 4 seconds have passed 
stopped executing mytest() because it 'Timed Out' 
continuing script execution past call of mytest() 
+0

如果'beBusyFor'在内部使用多处理会工作吗? – Greg

+0

@Dave只是尝试一下,如果它的工作,报告回来。还没有测试过这种情况,所以我认为它应该在没有父母的情况下留下一些乱七八糟的过程并不重要,因此不应该考虑在内。 – Claudio

+0

没有雪茄结束儿童进程不幸:(:( – Greg