The timeout decorator in Python is used to limit the execution time of a function. If the function runs longer than the specified time, it raises a TimeoutException. This is particularly useful in scenarios where you want to ensure a function doesn't hang indefinitely.

Source Code

import signal

class TimeoutException(Exception):
    pass

def timeout(seconds):
    def decorator(func):
        def handler(signum, frame):
            raise TimeoutException(f"Function {func.__name__} timed out after {seconds} seconds")

        def wrapper(*args, **kwargs):
            signal.signal(signal.SIGALRM, handler)
            signal.alarm(seconds)
            try:
                result = func(*args, **kwargs)
            finally:
                signal.alarm(0)
            return result

        return wrapper
    return decorator

@timeout(5)
def long_running_function():
    import time
    time.sleep(10)

try:
    long_running_function()
except TimeoutException as e:
    print(e)  # Output: Function long_running_function timed out after 5 seconds

 

Explanation

  1. Signal Handling: The signal module is used to set an alarm signal that triggers after the specified time.

     
  2. TimeoutException: A custom exception is raised when the function exceeds the allotted time.

     
  3. Decorator Structure: The timeout decorator wraps the target function and manages the timing logic using signal.

 

Use Cases

  • Network Requests: Limit the time spent waiting for network responses.
     
  • Long Computations: Prevent computationally expensive functions from running indefinitely.
     
  • Resource Management: Ensure functions accessing limited resources do not monopolize them.

 

Limitations

  • Platform Dependency: The signal module works only on Unix-based systems. => To avoid that, we can use some public services, ex: Sentry to notify errors

     
  • Thread Safety: Not suitable for multithreaded applications, as signals are process-wide.

By incorporating a timeout decorator, you can make your programs more robust and prevent potential hang-ups due to long-running functions.