2017-04-11 39 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