Jendas
Jendas

Reputation: 3579

How to timeout function in python, timeout less than a second

Specification of the problem:

I'm searching through really great amount of lines of a log file and I'm distributing those lines to groups in order to regular expressions(RegExses) I have stored using the re.match() function. Unfortunately some of my RegExses are too complicated and Python sometimes gets himself to backtracking hell. Due to this I need to protect it with some kind of timeout.

Problems:

I've spent this morning searching for solution to this question but I did not find any satisfactory answer.

Upvotes: 21

Views: 11978

Answers (2)

mrksharif
mrksharif

Reputation: 89

This is how we can define a timeout slow_function function but it doesn't stop the slow_function even after raising exception:

import threading, time

class TimeoutError(Exception):
    pass

def slow_function():
    time.sleep(1000)
    return "Done"

def run_with_timeout(func, timeout):
    def target():
        nonlocal result
        result = func()

    result = None
    thread = threading.Thread(target=target)
    thread.start()
    thread.join(timeout)
    if thread.is_alive():
        raise TimeoutError("Function timed out")
    return result

try:
    result = run_with_timeout(slow_function, 3)
except TimeoutError:
    print("Function timed out")
else:
    print("Function returned:", result)

Upvotes: 0

Jendas
Jendas

Reputation: 3579

Solution:

I've just modified a script posted here: Timeout function if it takes too long to finish.

And here is the code:

from functools import wraps
import errno
import os
import signal

class TimeoutError(Exception):
    pass

def timeout(seconds=10, error_message=os.strerror(errno.ETIME)):
    def decorator(func):
        def _handle_timeout(signum, frame):
            raise TimeoutError(error_message)

        def wrapper(*args, **kwargs):
            signal.signal(signal.SIGALRM, _handle_timeout)
            signal.setitimer(signal.ITIMER_REAL,seconds) #used timer instead of alarm
            try:
                result = func(*args, **kwargs)
            finally:
                signal.alarm(0)
            return result
        return wraps(func)(wrapper)
    return decorator

And then you can use it like this:

from timeout import timeout 
from time import time

@timeout(0.01)
def loop():
    while True:
       pass
try:
    begin = time.time()
    loop()
except TimeoutError, e:
    print "Time elapsed: {:.3f}s".format(time.time() - begin)

Which prints

Time elapsed: 0.010s

Upvotes: 44

Related Questions