如果卡住 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 秒,如何从函数返回? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

debian系统启动卡住,需要等待大约90秒才能进系统的解决办法

如何从函数返回向量引用?

从函数返回对象时调用C ++中的复制构造函数?

如何从 Python 中的函数返回多个值? [复制]

如何从我的异步函数返回一个值? [复制]

如果 python 函数返回多个值,我该如何使用它的返回值? [复制]