This works with CPython 2 (tested since 2.7) and does not explicitly use signals, but the CPython interpreter loop. Thus, you still have to process non-Python blocks in I / O calls and similar (for example, you must set socket.timeout ). In addition, it has possible expensive runtimes (you can force it to check the timeout for every * n-th call to make it a little easier).
However, it helps for a specific class of problems (such as computing). If you want it to coexist with a profiler, you will have to invest some work.
import sys import time class WatchdogTimeoutError(RuntimeError): """Raised in case of runtime limit violations.""" def sleeper(tick): """Endless loop.""" while True: time.sleep(tick) def watchdog(timeout, code, *args, **kwargs): "Time-limited execution." def tracer(frame, event, arg, start=time.time()): "Helper." now = time.time() if now > start + timeout: raise WatchdogTimeoutError(start, now) return tracer if event == "call" else None old_tracer = sys.gettrace() try: sys.settrace(tracer) code(*args, **kwargs) finally: sys.settrace(old_tracer) def demo(): """Show timeout executor.""" try: watchdog(5, sleeper, 0.1) except WatchdogTimeoutError, exc: start, abort = exc.args print "Aborted after %.3f secs" % (abort - start,) else: print "Ended" if __name__ == "__main__": demo()
source share