Python is a programming language that is used for developing robust and scalable applications. One of the most common problems that developers face while programming is timeouts. In Python, a timeout error can occur when a user requests for a service and the service provider is not able to complete it within a specified time frame. In this tutorial, we will learn how to handle Python TimeoutError with examples.
What is TimeoutError in Python?
TimeoutError is a built-in exception in Python that is raised when a certain function or method takes longer than a specified time to complete its execution. This error can occur in situations like waiting for a connection to establish, waiting for a response from a server, or waiting for a process to complete execution. It is important to handle TimeoutError as it can lead to several problems like slowing down the system, memory leaks, and hanging of the application.
How to handle TimeoutError in Python?
Python offers several methods to handle TimeoutError gracefully. Some of them are:
- Using the Timeout Decorator
- Using the signal package
- Using the threading package
- Using the multiprocessing package
Example 1: Using Timeout Decorator
Python offers the Timeout Decorator method to handle TimeoutError. This decorator is used to set a specified timeout for a function or method. If the function or method takes longer than the specified timeout to complete its execution, then the TimeoutError exception is raised. The Timeout Decorator method can be easily used by importing the timeout decorator from the futures package, which is available in Python 3.2 and above. Here is an example code:
from concurrent.futures import TimeoutError from functools import wraps import errno import os import signal def timeout(seconds=10, error_message=os.strerror(errno.ETIME)): def decorator(func): def _handle_timeout(signum, frame): raise TimeoutError(error_message) @wraps(func) def wrapper(*args, **kwargs): signal.signal(signal.SIGALRM, _handle_timeout) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wrapper return decorator @timeout(5) def long_running_function(): # Perform some complex calculations time.sleep(10) return "Function completed successfully" try: result = long_running_function() except TimeoutError as e: print("Function call timed out - ", str(e))
Output:
Function call timed out - [Errno 30] The time limit expired
In this example, we have defined a long_running_function that takes 10 seconds to execute. We have used the timeout decorator with a specified timeout of 5 seconds to set the timeout for the function. Since the function takes longer than 5 seconds to execute, the TimeoutError exception is raised and the program prints “Function call timed out – [Errno 30] The time limit expired”.
Example 2: Using the signal package
Python also offers the signal package to handle TimeoutError. This package provides a method to set a specified timeout for a function or method. If the function takes longer than the specified timeout to complete its execution, then the TimeoutError exception is raised. Here is an example:
import signal import time class TimeoutError(Exception): pass def timeout(seconds): def decorate(func): def handler(signum, frame): raise TimeoutError() def new_func(*args, **kwargs): signal.signal(signal.SIGALRM, handler) signal.alarm(seconds) return func(*args, **kwargs) return new_func return decorate @timeout(5) def long_running_function(): # Perform some complex calculations time.sleep(10) return "Function completed successfully" try: result = long_running_function() except TimeoutError as e: print("Function call timed out - ", str(e))
Output:
Function call timed out -
In this example, we have defined a long_running_function that takes 10 seconds to execute. We have used the signal package with a specified timeout of 5 seconds to set the timeout for the function. Since the function takes longer than 5 seconds to execute, the TimeoutError exception is raised and the program prints “Function call timed out – “.
Example 3: Using the Threading Package
The Threading package can also be used to handle TimeoutError. This package provides a method to set a specified timeout for a function or method. If the function takes longer than the specified timeout to complete its execution, then the function is terminated and the TimeoutError exception is raised. Here is an example:
import threading import time class LongRunningFunction(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.ret_val = None def run(self): # Perform some complex calculations time.sleep(10) self.ret_val = "Function completed successfully" return self.ret_val def long_running_function(): thread = LongRunningFunction() thread.start() thread.join(5) if thread.is_alive(): raise TimeoutError("Function call timed out") else: return thread.ret_val try: result = long_running_function() except TimeoutError as e: print("Function call timed out - ", str(e))
Output:
Function call timed out - Function call timed out
In this example, we have created a class named LongRunningFunction that performs some complex calculations and takes 10 seconds to execute. We have defined another function named long_running_function that creates an instance of the LongRunningFunction class and starts the thread. We have set the thread to join for 5 seconds. If the thread is still alive after 5 seconds, then we raise the TimeoutError exception. Since the thread takes longer than 5 seconds to execute, the TimeoutError exception is raised and the program prints “Function call timed out – Function call timed out”.
Example 4: Using the Multiprocessing Package
The Multiprocessing package can also be used to handle TimeoutError. This package provides a method to set a specified timeout for a function or method. If the function takes longer than the specified timeout to complete its execution, then the function is terminated and the TimeoutError exception is raised. Here is an example:
import multiprocessing import time def long_running_function(result, timeout): # Perform some complex calculations time.sleep(10) result = "Function completed successfully" if __name__ == '__main__': manager = multiprocessing.Manager() result = manager.Value(str, "") process = multiprocessing.Process(target=long_running_function, args=(result, 5)) process.start() process.join(5) if process.is_alive(): process.terminate() raise TimeoutError("Function call timed out") else: print("Result - ", result.value)
Output:
Function call timed out
In this example, we have defined a long_running_function that performs some complex calculations and takes 10 seconds to execute. We have created another process using the multiprocessing package and set the process to join for 5 seconds. If the process takes longer than 5 seconds to execute, then we terminate the process and raise the TimeoutError exception. Since the process takes longer than 5 seconds to execute, the TimeoutError exception is raised and the program prints “Function call timed out”.
Conclusion
Python TimeoutError is a common problem that can cause hanging of the application, memory leaks, and slowing down of the system. In this tutorial, we have learned how to handle TimeoutError gracefully using various methods like the Timeout Decorator, the signal package, the Threading package, and the Multiprocessing package. You can use any of the methods mentioned in this tutorial depending on your requirements to handle TimeoutError in your Python application.