How to Limit the Execution Time of a Function Call?

Rate this post

Problem Formulation

Say you need to call a potentially long function but you can only wait for a fixed time duration for the function to terminate.

If the function does terminate within the time interval, you take the function’s return value.

If the function does not terminate within the time interval, you want to take a default (fallback) value.

Example:

Given the following function long_function() that runs forever in an infinite while loop:

def long_function(n):
    while True:
        pass

In your main code, you want to run the function and wait for a certain number of seconds as given by variable max_wait—but not longer.

If the function doesn’t return anything within the given time constraint, you want to return a specified value by default (default_value).

Here’s how your run_function(func, max_wait, default_value) should work:

def run_function(f, max_wait, default_value):
    pass

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

The function run_function() attempts to execute the long_function() and waits for 5 seconds.

As long_function() doesn’t return any value within the specified time limit, run_function() aborts the function execution and returns the default value 'world' as specified in the function call for argument default_value.

How to implement the function run_function() in Python?

Solution

A platform-independent and portable way to limit the execution time of a function call, use the func_timeout.func_timeout() function of the func_timeout module.

Here’s the documentation of the function—but you don’t need to study it too thoroughly, I’ll show you a simple (minimal) example right afterward:

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

The function func_timeout runs the given function for up to timeout seconds and raises a FunctionTimedOut error if the timeout is exceeded.

If the func returns a value within the specified time, func_timeout passes that return value to the caller.

These are the arguments from the docs:

  • timeout: Maximum number of seconds to run func before terminating
  • func: The function to call
  • args: Any ordered arguments to pass to func
  • kwargs: Keyword arguments to pass to func

Let’s get this problem solved step by step!

Install and Import func_timeout

Before using the func_timeout module, you need to install it by running pip install func_timeout in your terminal, command line, or Powershell:

$ pip install func_timeout

Here’s how that looks in my Win Powershell:

To learn more about installing libraries, have a look at this guide.

After installation, you can import the func_timeout module and use the func_timeout() function with the same name in your Python code to limit the execution time of a given function.

Guided Solution Example

Example: Let’s have a look at the following code snippet that showcases how to solve the specified problem—I’ll explain it subsequently after the code:

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

The run_function() implementation calls func_timeout.func_timeout(max_wait, long_function) to call long_function() without arguments and wait for max_wait seconds.

If the long_funcion() doesn’t terminate within the specified time interval, an error is raised and caught by the except branch before the return value of long_function can be forwarded to the caller of run_function().

The default value is returned—which is 'world' in our example.

As the function long_function() took forever, it couldn’t return the string 'universe', so our code uses the default output 'world'.

Function Goes Through

If the function doesn’t take too long to run, the default value is ignored:

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

Thus, the output of the function execution is 'universe' which is the return value of the long_function() that didn’t take too long in this example as we commented out the infinite while loop.

Function Arguments

But what if you want to specify function arguments?

You can do so by using the args argument of the func_timeout.func_timeout() function that takes a sequence (e.g., list) of values and passes these values into the argument of the function to be executed.

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)

Of course, you can also pass multiple arguments by specifying a list of length larger than 1 as an argument to func_timeout() like so: args = [my_arg_1, my_arg_2, ..., my_arg_n] will call the function long_function(my_arg_1, my_arg_2, ..., my_arg_n).