Timeout Decorator
The `timeout-decorator` library provides a simple Python decorator to enforce execution time limits on functions. It primarily uses Unix signals for timeouts in the main thread but offers a multiprocessing strategy for use in other threads or on Windows. The library is currently at version 0.5.0, with its last release in 2020, but it remains a commonly used solution for function timeouts.
Warnings
- gotcha The default signal-based timeout strategy (when `use_signals=True` or omitted) only works in the main thread on Unix-like operating systems. It is not compatible with Windows or functions running in non-main threads. For these cases, you must explicitly pass `use_signals=False` to switch to a multiprocessing-based strategy.
- gotcha When using the multiprocessing strategy (`use_signals=False`), all arguments passed to the decorated function and any values returned by it must be picklable. If they are not, the function call will fail with a `PicklingError`.
- gotcha Signal-based timeouts do not support nesting. If an outer function and an inner function are both decorated with `timeout` using signals, the inner timeout will cancel and override the outer one. Only one `SIGALRM` can be active per process.
- gotcha Functions decorated with `@timeout` can inadvertently suppress `TimeoutError` if they broadly catch exceptions (e.g., `except Exception:`). This can prevent the timeout mechanism from effectively terminating the function or raising the expected error.
- gotcha Some users have reported compatibility issues with `timeout-decorator` on Python 3.8 and newer versions, specifically related to changes in internal function naming, which could lead to `AttributeError` or unexpected behavior.
Install
-
pip install timeout-decorator
Imports
- timeout
from timeout_decorator import timeout
Quickstart
import time
import timeout_decorator
@timeout_decorator.timeout(5)
def long_running_function():
print("Starting long_running_function...")
for i in range(1, 10):
time.sleep(1)
print(f"{i} seconds have passed inside function")
print("long_running_function completed.")
@timeout_decorator.timeout(3, use_signals=False)
def another_long_running_function():
print("Starting another_long_running_function with multiprocessing strategy...")
for i in range(1, 10):
time.sleep(1)
print(f"{i} seconds have passed inside function")
print("another_long_running_function completed.")
if __name__ == '__main__':
print("--- Testing signal-based timeout ---")
try:
long_running_function()
except timeout_decorator.TimeoutError:
print("long_running_function timed out after 5 seconds.")
print("\n--- Testing multiprocessing-based timeout ---")
try:
another_long_running_function()
except timeout_decorator.TimeoutError:
print("another_long_running_function timed out after 3 seconds.")