Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timeout a function (windows)?

I am trying to implement timeout for a particular function. I have checked many of the questions in SE and couldn't find any solution which fits my problem, because:

  1. I am running python in Windows
  2. Timeout is applied on a python function which I don't have control on, i.e. it is defined in an already designed module.
  3. The python function is not a subprocess

I am having a already designed custom module (say MyModule) developed for particular tasks, and there are functions defined in it. One of the function (say MyFunc) has a tendency to run forever because of external factors, and I just don't want the python script to hang.

I am planning to add a timeout feature, as said below pseudocode:

import MyModule

set_timeout(T)
MyResult=MyModule.MyFunc()

#Come to this part of script after execution of MyFunc() or after T seconds (the latter on priority)
if Timeout occurred:
    print 'MyFunc did not execute completely'
else:
    print 'MyFunc completed'

But I am not sure which module can be used to achieve this on python. Note that I am a newbie, and all the scripts I have written are directly based on SE Answers or Python Documentation.

like image 661
punarvak Avatar asked Feb 17 '14 11:02

punarvak


People also ask

What is timeout function in Python?

Timeout is very useful when you want to limit the max time for calling a function or running a command.

How do you call a timeout function in Python?

Then it's as simple as this to timeout a test or any function you like: @timeout(5.0) # if execution takes longer than 5 seconds, raise a TimeoutError def test_base_regression(self): ... Be careful since this does not terminate the function after timeout is reached!


2 Answers

I think a good way to approach this is to create a decorator and use the Thread.join(timeout=seconds) method. Bear in mind that there's no good way to kill the thread, so it will continue to run in the background, more or less, as long as your program is running.

First, create a decorator like this:

from threading import Thread
import functools

def timeout(timeout):
    def deco(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            res = [Exception('function [%s] timeout [%s seconds] exceeded!' % (func.__name__, timeout))]
            def newFunc():
                try:
                    res[0] = func(*args, **kwargs)
                except Exception as e:
                    res[0] = e
            t = Thread(target=newFunc)
            t.daemon = True
            try:
                t.start()
                t.join(timeout)
            except Exception as je:
                print ('error starting thread')
                raise je
            ret = res[0]
            if isinstance(ret, BaseException):
                raise ret
            return ret
        return wrapper
    return deco

Then, do something like this:

func = timeout(timeout=16)(MyModule.MyFunc)
try:
    func()
except:
    pass #handle errors here

You can use this decorator anywhere you need with something like:

@timeout(60)
def f():
    ...
like image 187
acushner Avatar answered Sep 23 '22 11:09

acushner


@acushner's answer adapted for python 3.5:

from threading import Thread
import functools

def timeout(seconds_before_timeout):
    def deco(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            res = [Exception('function [%s] timeout [%s seconds] exceeded!' % (func.__name__, seconds_before_timeout))]
            def newFunc():
                try:
                    res[0] = func(*args, **kwargs)
                except Exception as e:
                    res[0] = e
            t = Thread(target=newFunc)
            t.daemon = True
            try:
                t.start()
                t.join(seconds_before_timeout)
            except Exception as e:
                print('error starting thread')
                raise e
            ret = res[0]
            if isinstance(ret, BaseException):
                raise ret
            return ret
        return wrapper
    return deco
like image 24
Almenon Avatar answered Sep 22 '22 11:09

Almenon