2017-05-28 55 views
1

我一直在试图创建一个超时,告诉我的代码的一部分,如果它在一定的时间内没有达到结果,继续前进。休息功能,并在一段时间后过去 - Python

我测试了从这里发布的主要答案中的代码:break the function after certain time,它的工作原理非常完美,但是当我使用我的代码实现它时无法正常工作。

无论“Try”内的代码块执行多长时间,TimeoutException都不会被触发。代码块内的计时器始终以大于5秒的时间间隔打印,即使代码花费的时间超过signal.alarm(5)允许的5秒钟时间,甚至不应该调用打印操作。

你能想到TimeoutException没有被触发的任何原因,我该如何解决它?

import signal 
import time 

def evaluateList(dataDictionaryList): 
    newDataDict = [] 
    count = 0 


    class TimeoutException(Exception): 
     pass 

    def timeout_handler(signum, frame): 
     raise TimeoutException 

    signal.signal(signal.SIGALRM, timeout_handler) 


    for dataDictionary in dataDictionaryList: 

     signal.alarm(5) 

     try: 
      startTime = time.time() 
      newDataDict.append(functionThatMightHang(dataDictionary)) 
      print(count + 1, ' Time to evaluate: ', time.time() - startTime) 
      count+=1 

     except TimeoutException: 
      print('took too long') 
      continue 
     else: 
      signal.alarm(0) 

    return newDataDict 

回答

1

它确实应该工作 - 除非里面functionThatMightHang一些代码块本身是捕捉和吞食你的TimeoutException异常。如果有一个try/except块捕获那里的光秃秃的Exception,并且忽略它并继续计算,这种事情就会发生。 (这是一个糟糕的编程习惯,甚至在Python的禅宗中也如此)。

如果您有权访问该函数源代码,寻找try/excecpt块并包含打印件以检查它,并捕获特定的异常,而不是裸露的除外。

如果不能深入到代码 - 你可以做一个单杆试图改变你TimeoutExceptionBaseException的底座(代替Exception)。

在任何情况下,您似乎都不是解决手头问题的最佳方法 - 信号与许多类型的代码很不协调,包括多线程或其他事件循环基于代码。此外,即使您的处理程序在适当的时候正确地引发了Python异常,但如果您的长时间运行的函数是本机代码,那么Python本身不会处理该异常(并因此将执行切换到except块),直到本机代码函数返回。我认为这是你的(唯一)问题,因为在这种情况下,下面的打印语句不会运行 - 这将花费超过5秒钟,并且它们执行except块。

真正的解决

你可能想尝试使用Python的concurrent.future模块来运行你的长期功能。通过这种方式,你可以在另一个线程中运行你的长期功能,或多或少透明的方式(甚至在另一个进程中,这将利用多个内核),并为执行指定一个超时参数--Python的并发。未来的机器将自行处理停止计算。

此示例适用于交互式解释,并提出了TimeoutError(一个由concurrent.futures使用,而不是一个自定义):

from concurrent.futures import ThreadPoolExecutor 
import time 

def long(): 
    time.sleep(3) 

p = ThreadPoolExecutor(1) 

f = p.submit(long); f.result(timeout=1)