toro: Synchronization primitives for Tornado coroutines

_images/toro.png

Toro logo by Musho Rodney Alan Greenblat

With Tornado’s gen module, you can turn Python generators into full-featured coroutines, but coordination among these coroutines is difficult without mutexes, semaphores, and queues.

Toro provides to Tornado coroutines a set of locking primitives and queues analogous to those that Gevent provides to Greenlets, or that the standard library provides to threads.

Important

Toro is completed and deprecated; its features have been merged into Tornado. Development of locks and queues for Tornado coroutines continues in Tornado itself.

The Wait / Notify Pattern

Toro’s primitives follow a “wait / notify pattern”: one coroutine waits to be notified by another. Let’s take Condition as an example:

>>> import toro
>>> from tornado import ioloop, gen
>>> loop = ioloop.IOLoop.current()
>>> condition = toro.Condition()
>>> @gen.coroutine
... def waiter():
...     print "I'll wait right here"
...     yield condition.wait()  # Yield a Future
...     print "I'm done waiting"
...
>>> @gen.coroutine
... def notifier():
...     print "About to notify"
...     condition.notify()
...     print "Done notifying"
...
>>> @gen.coroutine
... def runner():
...     # Yield two Futures; wait for waiter() and notifier() to finish
...     yield [waiter(), notifier()]
...     loop.stop()
...
>>> future = runner(); loop.start()
I'll wait right here
About to notify
Done notifying
I'm done waiting

Wait-methods take an optional deadline argument, which is either an absolute timestamp:

loop = ioloop.IOLoop.current()

# Wait up to 1 second for a notification
yield condition.wait(deadline=loop.time() + 1)

...or a datetime.timedelta for a deadline relative to the current time:

# Wait up to 1 second
yield condition.wait(deadline=datetime.timedelta(seconds=1))

If there’s no notification before the deadline, the Toro-specific Timeout exception is raised.

The Get / Put Pattern

Queue and its subclasses support methods Queue.get() and Queue.put(). These methods are each both a wait-method and a notify-method:

  • Queue.get() waits until there is an available item in the queue, and may notify a coroutine waiting to put an item.
  • Queue.put() waits until the queue has a free slot, and may notify a coroutine waiting to get an item.

Queue.get() and Queue.put() accept deadlines and raise Timeout if the deadline passes.

See the Producer-consumer example.

Additionally, JoinableQueue supports the wait-method JoinableQueue.join() and the notify-method JoinableQueue.task_done().

Source

Is on GitHub: https://github.com/ajdavis/toro

Bug Reports and Feature Requests

Also on GitHub: https://github.com/ajdavis/toro/issues

Indices and tables