Función de tiempo de espera si se demora mucho en finalizar

Tengo un script de shell que recorre un archivo de texto que contiene la URL: s que quiero visitar y tomar capturas de pantalla.

Todo esto es hecho y simple. El script inicializa una clase que cuando se ejecuta crea una captura de pantalla de cada sitio en la lista. Algunos sitios tardan mucho, mucho tiempo en cargarse, y algunos pueden no cargarse en absoluto. Por lo tanto, quiero envolver la función screengrabber en un script de tiempo de espera, haciendo que la función devuelva False si no se puede finalizar en 10 segundos.

Estoy contento con la solución más simple posible, ¿quizás configurando un temporizador asíncrono que devolverá Falso después de 10 segundos sin importar lo que realmente ocurra dentro de la función?

El proceso para el tiempo de espera de una operación se describe en la documentación de la señal .

La idea básica es usar manejadores de señales para progtwigr una alarma durante un intervalo de tiempo y generar una excepción una vez que el temporizador caduque.

Tenga en cuenta que esto solo funcionará en UNIX.

Aquí hay una implementación que crea un decorador (guarda el siguiente código como timeout.py ).

 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.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return wraps(func)(wrapper) return decorator 

Esto crea un decorador llamado @timeout que se puede aplicar a cualquier función de larga ejecución.

Entonces, en el código de tu aplicación, puedes usar el decorador así:

 from timeout import timeout # Timeout a long running function with the default expiry of 10 seconds. @timeout def long_running_function1(): ... # Timeout after 5 seconds @timeout(5) def long_running_function2(): ... # Timeout after 30 seconds, with the error "Connection timed out" @timeout(30, os.strerror(errno.ETIMEDOUT)) def long_running_function3(): ... 

Reescribí la respuesta de David usando la statement with , te permite hacer esto:

 with timeout(seconds=3): time.sleep(4) 

Lo que elevará un TimeoutError.

El código sigue usando signal y, por lo tanto, solo UNIX:

 import signal class timeout: def __init__(self, seconds=1, error_message='Timeout'): self.seconds = seconds self.error_message = error_message def handle_timeout(self, signum, frame): raise TimeoutError(self.error_message) def __enter__(self): signal.signal(signal.SIGALRM, self.handle_timeout) signal.alarm(self.seconds) def __exit__(self, type, value, traceback): signal.alarm(0)