如果卡住 90 秒,如何从函数返回? [复制]
Posted
技术标签:
【中文标题】如果卡住 90 秒,如何从函数返回? [复制]【英文标题】:How to return from function if got stuck for 90 seconds? [duplicate] 【发布时间】:2012-01-08 02:32:56 【问题描述】:可能重复:Timeout on a Python function call
我想实现,当函数需要超过 90 秒才能完成时,它应该在超时时立即返回。有什么方法可以实现吗?
def abc(string):
import re
if re.match('some_pattern', string):
return True
else:
return False
abc('some string to match')
已编辑
请下载this测试文件。如果发生超时错误,我创建了一个线程类并在线程内引发异常。但是线程仍然存在,因为即使在异常之后它也会打印i am still alive :)
。为什么异常不会强制线程停止?
【问题讨论】:
这类问题通常会得到涉及线程的答案,signal.alarm()
、signal.setitmer()
等。小心这些答案——它们可能依赖于抛出的 Python 异常,但我怀疑 Python 异常可以中断re.match()
。 (不确定正确答案。也许使用子进程,并在 90 秒后将其终止。)
@aix:虽然链接的问题非常相似,但没有一个答案在这里真正适用。只有检查过的答案才会起作用,但它会使停滞的功能在后台运行并消耗 CPU 时间。这就是我不投票关闭的原因。
【参考方案1】:
我已编辑我的帖子以使用更简单的jcollado's idea。
multiprocessing.Process.join 方法有一个超时参数,您可以像这样使用它:
import multiprocessing as mp
import time
import logging
import re
logger = logging.getLogger(__name__)
def abc(string, result, wait = 0):
time.sleep(wait)
result.put(bool(re.match('some_pattern', string)))
if __name__ == '__main__':
logging.basicConfig(level = logging.DEBUG,
format = '%(asctime)s: %(message)s',
datefmt = '%H:%M:%S', )
result = mp.Queue()
proc = mp.Process(target = abc, args = ('some_pattern to match', result))
proc.start()
proc.join(timeout = 5)
if proc.is_alive():
proc.terminate()
else:
logger.info(result.get())
proc = mp.Process(target = abc, args = ('some string to match', result, 20))
proc.start()
proc.join(timeout = 5)
if proc.is_alive():
logger.info('Timed out')
proc.terminate()
else:
logger.info(result.get())
产量
12:07:59: True
12:08:04: Timed out
请注意,您会在 5 秒内收到“超时”消息,即使 abc('some string',20)
需要大约 20 秒才能完成。
【讨论】:
子进程中的操作会被中断,还是会继续消耗CPU时间? @Sven:您的评论可能在我编辑之前——pool.terminate
将中断子进程。
@SvenMarnach,Pool.terminate()
的文档说“立即停止工作进程而不完成未完成的工作。当池对象被垃圾收集时,将立即调用 terminate()。” Process.terminate()
说“终止进程。在 Unix 上,这是使用 SIGTERM 信号完成的;在 Windows 上使用 TerminateProcess()。请注意,退出处理程序和 finally 子句等将不会被执行。”所以我认为你可以假设它在这里需要。
@Duncan:谢谢。正如 unutbu 所说,我的评论是在编辑之前。
@unutbu 我尝试了你的方法,我在简单的函数上工作得很好,但是当我在我的主程序中使用它时,出现了以下异常Traceback (most recent call last): File "C:\Python27\lib\threading.py", line 552, in __bootstrap_inner self.run() File "C:\Python27\lib\threading.py", line 505, in run self.__target(*self.__args, **self.__kwargs) File "C:\Python27\lib\multiprocessing\pool.py", line 313, in _handle_tasks put(task) PicklingError: Can't pickle <type 'thread.lock'>: attribute lookup thread.lock failed
。【参考方案2】:
处理此问题的一种方法是将此任务放入线程中,并在 90 秒后使用看门狗将其杀死。
Here's a recipe at ActiveState.
编辑:显然,配方本身并不是完整的解决方案。如果工作线程已完成,您将拥有一个每隔 x 秒检查一次的看门狗线程,或者您将转到像 Michael Ford's simple event framework 这样的事件框架。
【讨论】:
这是一个很好的食谱,请等到我实施它。感谢您的帮助。 这个配方完全不适用于给定的问题。它依赖于工作线程轮询一些标志。你会如何让re.match()
投票? (-1)以上是关于如果卡住 90 秒,如何从函数返回? [复制]的主要内容,如果未能解决你的问题,请参考以下文章