0

For example, I have a code like the following code in Python.

import time


def sleep(timeout: int) -> str:
    time.sleep(timeout ** 7 * 1000)
    return "Hello, world!"


result = sleep(5)

As you know, this code is very time consuming. I want to make it so that if the execution of the code takes more than 5 seconds, it will stop the execution and return a message like "function stopped". How can I do this?

I used different things in Python such as time, thread and signal, but I did not get the result I wanted and the program crashes.

  • On Unix-type systems you can utilise SIGALRM. See: https://docs.python.org/3/library/signal.html – DarkKnight Apr 04 '23 at 11:13
  • Does this answer your question? [Timeout on a function call](https://stackoverflow.com/questions/492519/timeout-on-a-function-call) – matszwecja Apr 04 '23 at 11:20

3 Answers3

1

You can use Decorator design pattern with signal

@timeout(seconds=5, default=None)
def function():

    pass

result = function()

This timeout decorator takes a number of seconds as an argument and a default value to return if the function times out. It then returns a decorator function that takes the target function as an argument, and returns a wrapper function that calls the target function with a timeout.

def timeout(seconds=5, default=None):

def decorator(func):

    @functools.wraps(func)
    def wrapper(*args, **kwargs):

        def handle_timeout(signum, frame):
            raise TimeoutError()

        signal.signal(signal.SIGALRM, handle_timeout)
        signal.alarm(seconds)

    
        result = func(*args, **kwargs)

        signal.alarm(0)

        return result

    return wrapper

return decorator
1

I don't really understand what do you mean by "time consuming" but anyway I've tried it with thread using python on windows and it works, you can use a global variable with a while and manage your function with a thread like this :

from threading import Thread

# Your execution time in seconds
maxExecutionTime = 5

# Define a flag variable (Like a sort of On/Off switch)
global stopWorking
stopWorking = False


# Your function
def thingsToDo():
    print("Function started")
    while not stopWorking:
        print("Function working")
        # Put your code here
        pass
    print("Function stopped")

# Create the thread that will start your function
thread = Thread(target=thingsToDo)

# Start the thread
thread.start()

# Join your thread with the execution time you want
thread.join(maxExecutionTime)

# Set off your flag switch to indicate that the thread should stop
stopWorking = True
TzRPheonix
  • 26
  • 6
0

For Unix-type systems you can use the SIGALRM signal to your advantage.

This is the class I use for this kind of thing with an example of usage at the end.

from signal import signal, alarm, SIGALRM
import time

class TimeoutError(Exception):
    ...

class Timeout:
    def __init__(self, seconds=1, message="Timed out"):
        self._seconds = seconds
        self._message = message

    @property
    def seconds(self):
        return self._seconds

    @property
    def message(self):
        return self._message
    
    @property
    def handler(self):
        return self._handler

    @handler.setter
    def handler(self, handler):
        self._handler = handler

    def handle_timeout(self, *_):
        raise TimeoutError(self.message)

    def __enter__(self):
        self.handler = signal(SIGALRM, self.handle_timeout)
        alarm(self.seconds)
        return self

    def __exit__(self, *_):
        alarm(0)
        signal(SIGALRM, self.handler)

# example of use

with Timeout(2): # time out after two seconds with default message
    try:
        time.sleep(10)
    except TimeoutError as e:
        print(e)
DarkKnight
  • 19,739
  • 3
  • 6
  • 22