Cooperative Timeouts Using gevent.Timeout

Cooperative timeouts can be implemented with the gevent.Timeout class, and the helper function gevent.with_timeout().

class Timeout(seconds=None, exception=None, ref=True, priority=-1)[source]

Bases: BaseException

Raise exception in the current greenlet after seconds have elapsed:

timeout = Timeout(seconds, exception)
timeout.start()
try:
    ...  # exception will be raised here, after *seconds* passed since start() call
finally:
    timeout.close()

Warning

You must always call close on a Timeout object you have created, whether or not the code that the timeout was protecting finishes executing before the timeout elapses (whether or not the Timeout exception is raised) This try/finally construct or a with statement is a good pattern. (If the timeout object will be started again, use cancel instead of close; this is rare. You must still close it when you are done.)

When exception is omitted or None, the Timeout instance itself is raised:

>>> import gevent
>>> gevent.Timeout(0.1).start()
>>> gevent.sleep(0.2)  
Traceback (most recent call last):
 ...
Timeout: 0.1 seconds

If the seconds argument is not given or is None (e.g., Timeout()), then the timeout will never expire and never raise exception. This is convenient for creating functions which take an optional timeout parameter of their own. (Note that this is not the same thing as a seconds value of 0.)

def function(args, timeout=None):
   "A function with an optional timeout."
   timer = Timeout(timeout)
   with timer:
      ...

Caution

A seconds value less than 0.0 (e.g., -1) is poorly defined. In the future, support for negative values is likely to do the same thing as a value of None or 0

A seconds value of 0 requests that the event loop spin and poll for I/O; it will immediately expire as soon as control returns to the event loop.

Use As A Context Manager

To simplify starting and canceling timeouts, the with statement can be used:

with gevent.Timeout(seconds, exception) as timeout:
    pass  # ... code block ...

This is equivalent to the try/finally block above with one additional feature: if exception is the literal False, the timeout is still raised, but the context manager suppresses it, so the code outside the with-block won’t see it.

This is handy for adding a timeout to the functions that don’t support a timeout parameter themselves:

data = None
with gevent.Timeout(5, False):
    data = mysock.makefile().readline()
if data is None:
    ...  # 5 seconds passed without reading a line
else:
    ...  # a line was read within 5 seconds

Caution

If readline() above catches and doesn’t re-raise BaseException (for example, with a bare except:), then your timeout will fail to function and control won’t be returned to you when you expect.

Catching Timeouts

When catching timeouts, keep in mind that the one you catch may not be the one you have set (a calling function may have set its own timeout); if you going to silence a timeout, always check that it’s the instance you need:

timeout = Timeout(1)
timeout.start()
try:
    ...
except Timeout as t:
    if t is not timeout:
        raise # not my timeout
finally:
    timeout.close()

Changed in version 1.1b2: If seconds is not given or is None, no longer allocate a native timer object that will never be started.

Changed in version 1.1: Add warning about negative seconds values.

Changed in version 1.3a1: Timeout objects now have a close() method that must be called when the timeout will no longer be used to properly clean up native resources. The with statement does this automatically.

__enter__()[source]

Start and return the timer. If the timer is already started, just return it.

__exit__(typ, value, tb)[source]

Stop the timer.

Changed in version 1.3a1: The underlying native timer is also stopped. This object cannot be used again.

cancel()[source]

If the timeout is pending, cancel it. Otherwise, do nothing.

The timeout object can be started again. If you will not start the timeout again, you should use close() instead.

close()[source]

Close the timeout and free resources. The timer cannot be started again after this method has been used.

start()[source]

Schedule the timeout.

classmethod start_new(timeout=None, exception=None, ref=True, _one_shot=False)[source]

Create a started Timeout.

This is a shortcut, the exact action depends on timeout’s type:

  • If timeout is a Timeout, then call its start() method if it’s not already begun.

  • Otherwise, create a new Timeout instance, passing (timeout, exception) as arguments, then call its start() method.

Returns the Timeout instance.

property pending

True if the timeout is scheduled to be raised.

Next page: gevent.socket – Cooperative low-level networking interface