如何在python中限制一个函数调用的执行时间?

1,665 阅读3分钟

问题的提出

假设你需要调用一个潜在的长函数,但你只能等待一个固定的时间段来终止该函数。

如果该函数在该时间间隔内终止,你将获得该函数的返回值。

如果函数没有在时间间隔内结束,你要取一个默认的(回退)值。

例子。

给出以下函数long_function() ,在一个无限的while循环中永远运行。

def long_function(n):
    while True:
        pass

在你的主代码中,你想运行该函数并等待一定的秒数,如变量max_wait 所示--但不能更长。

如果该函数在给定的时间限制内没有返回任何东西,你想默认返回一个指定的值(default_value )。

下面是你的run_function(func, max_wait, default_value) 应该如何工作。

def run_function(f, max_wait, default_value):
    pass

x = run_function(long_function, 5, 'world')
print(x)
# world

函数run_function() 试图执行long_function() ,并等待5 秒。

由于long_function() 在指定的时限内没有返回任何值,run_function() 终止函数的执行,并返回在函数调用中为参数default_value 指定的默认值'world'

如何在Python中实现函数run_function()

解决方法

一个独立于平台且可移植的方法是限制函数调用的执行时间,使用模块的func_timeout.func_timeout() 函数。 [func_timeout](https://pypi.org/project/func-timeout/)模块。

这里是该函数的文档--但你不需要研究得太透彻,紧接着我将给你看一个简单的(最小的)例子。

func_timeout(timeout, func, args=(), kwargs=None)

函数func_timeout ,运行给定的函数,最长时间为timeout ,如果超过timeout ,就会引发FunctionTimedOut 的错误。

如果func 在指定的时间内返回一个值,func_timeout 将该返回值传递给调用者。

这些是文档中的参数。

  • timeout:终止前运行func 的最大秒数
  • func:要调用的函数
  • args:任何有序的参数要传递给func
  • kwargs:要传递的关键字参数func

让我们一步一步地解决这个问题吧!

安装和导入 func_timeout

在使用func_timeout 模块之前,你需要通过在终端、命令行或Powershell中运行pip install func_timeout 来安装它。

$ pip install func_timeout

下面是在我的Win Powershell中的样子。

要了解更多关于安装库的信息,请看这个指南

安装后,你可以导入func_timeout 模块,并在你的Python代码中使用同名的func_timeout() 函数来限制特定函数的执行时间。

指导性解决方案实例

例子。让我们看一下下面的代码片段,它展示了如何解决指定的问题--我将在代码之后进行解释。

import func_timeout


def long_function():
    while True: pass
    return 'universe'


def run_function(f, max_wait, default_value):
    try:
        return func_timeout.func_timeout(max_wait, long_function)
    except func_timeout.FunctionTimedOut:
        pass
    return default_value

x = run_function(long_function, 5, 'world')

print(x)
# world

run_function() 的实现调用func_timeout.func_timeout(max_wait, long_function) ,在没有参数的情况下调用long_function() ,并等待max_wait 秒。

如果long_funcion() 在指定的时间间隔内没有终止,在long_function 的返回值转发给run_function() 的调用者之前,会引发一个错误并被 except 分支捕获。

默认值被返回--在我们的例子中是'world'

由于函数long_function() 花了很长时间,它不能返回字符串'universe' ,所以我们的代码使用默认输出'world'

函数通过

如果函数的运行时间不长,默认值就会被忽略。

import func_timeout


def long_function():
    # while True: pass
    return 'universe'


def run_function(f, max_wait, default_value):
    try:
        return func_timeout.func_timeout(max_wait, long_function)
    except func_timeout.FunctionTimedOut:
        pass
    return default_value

x = run_function(long_function, 5, 'world')

print(x)
# universe

因此,函数执行的输出是'universe' ,这是本例中没有花费太长时间的long_function() ,因为我们注释了无限的while循环

函数参数

但是如果你想指定函数参数呢?

你可以通过使用func_timeout.func_timeout() 函数的args 参数来实现,该函数接收一个数值序列(例如,列表),并将这些数值传递给要执行的函数的参数。

import func_timeout


def long_function(my_argument):
    print(my_argument)
    while True: pass
    return 'universe'


def run_function(f, my_argument, max_wait, default_value):
    try:
        return func_timeout.func_timeout(max_wait,
                                         long_function,
                                         args=[my_argument])
    except func_timeout.FunctionTimedOut:
        pass
    return default_value

x = run_function(long_function, 'started execution', 5, 'world')

print(x)

当然,你也可以通过指定一个长度大于1的列表作为func_timeout() 的参数来传递多个参数,像这样:args = [my_arg_1, my_arg_2, ..., my_arg_n] 将调用函数long_function(my_arg_1, my_arg_2, ..., my_arg_n)