I have timeout
context manager that works perfectly with signals but it raises error in multithread mode because signals work only in main thread.
def timeout_handler(signum, frame):
raise TimeoutException()
@contextmanager
def timeout(seconds):
old_handler = signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(seconds)
try:
yield
finally:
signal.alarm(0)
signal.signal(signal.SIGALRM, old_handler)
I've seen decorator implementation of timeout
but I don't know how to pass yield
inside class derived from threading.Thread
. My variant won't work.
@contextmanager
def timelimit(seconds):
class FuncThread(threading.Thread):
def run(self):
yield
it = FuncThread()
it.start()
it.join(seconds)
if it.isAlive():
raise TimeoutException()
I cannot see a way of doing what you are proposing with a context manager, you cannot
yield
the flow from one thread to another. What I would do is wrap your function with an interrutable thread with the timeout. Here is a recipe for that.You will have an extra thread and the syntax won't be as nice but it would work.
Timeouts for system calls are done with signals. Most blocking system calls return with EINTR when a signal happens, so you can use alarm to implement timeouts.
Here's a context manager that works with most system calls, causing IOError to be raised from a blocking system call if it takes too long.
If the code guarded by the context manager is loop-based, consider handling this the way people handle thread killing. Killing another thread is generally unsafe, so the standard approach is to have the controlling thread set a flag that's visible to the worker thread. The worker thread periodically checks that flag and cleanly shuts itself down. Here's how you can do something analogous with timeouts:
Here's a single-threaded usage example:
and a multithreaded one:
This approach is more intrusive than using signals but it works for arbitrary threads.
I know it's late but I'm only just reading this, but what about creating your own signaller/context manager? I'm new to python would love feedback from experienced devs this implementation.
This is based off of the answer from "Mr Fooz"
Use case: