From 7159718050f5980d51b0b5fd499ef07d88cfe26b Mon Sep 17 00:00:00 2001 From: "A. Jesse Jiryu Davis" Date: Mon, 30 Mar 2015 22:41:05 -0400 Subject: [PATCH] Document locks.Semaphore. --- docs/locks.rst | 65 +++++++++++++++++++++++++++++++++++++++++++++++- tornado/locks.py | 12 --------- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/docs/locks.rst b/docs/locks.rst index c9fd275c..c0ad5005 100644 --- a/docs/locks.rst +++ b/docs/locks.rst @@ -11,7 +11,7 @@ place of those from the standard library--they are meant to coordinate Tornado coroutines in a single-threaded app, not to protect shared objects in a multithreaded app.)* -.. testsetup:: +.. testsetup:: * from tornado import ioloop, gen, locks io_loop = ioloop.IOLoop.current() @@ -108,3 +108,66 @@ multithreaded app.)* About to set the event Not waiting this time Done + + Semaphore + --------- + .. autoclass:: Semaphore + :members: + + Semaphores limit access to a shared resource. To allow access for two + workers at a time: + + .. testsetup:: semaphore + + from tornado import gen + + # Ensure reliable doctest output. + waits = [0.1, 0.2, 0.1] + + @gen.coroutine + def use_some_resource(): + yield gen.sleep(waits.pop()) + + .. testcode:: semaphore + + sem = locks.Semaphore(2) + + @gen.coroutine + def worker(worker_id): + yield sem.acquire() + try: + print("Worker %d is working" % worker_id) + yield use_some_resource() + finally: + print("Worker %d is done" % worker_id) + sem.release() + + @gen.coroutine + def runner(): + # Join all workers. + yield [worker(i) for i in range(3)] + + io_loop.run_sync(runner) + + .. testoutput:: semaphore + + Worker 0 is working + Worker 1 is working + Worker 0 is done + Worker 2 is working + Worker 1 is done + Worker 2 is done + + Workers 0 and 1 are allowed to run concurrently, but worker 2 waits until + the semaphore has been released once, by worker 0. + + `.acquire` is a context manager, so ``worker`` could be written as:: + + @gen.coroutine + def worker(worker_id): + with (yield sem.acquire()): + print("Worker %d is working" % worker_id) + yield use_some_resource() + + # Now the semaphore has been released. + print("Worker %d is done" % worker_id) diff --git a/tornado/locks.py b/tornado/locks.py index bdf15a2c..10a40f4c 100644 --- a/tornado/locks.py +++ b/tornado/locks.py @@ -165,18 +165,6 @@ class Semaphore(_TimeoutGarbageCollector): minus the number of `.acquire` calls, plus an initial value. The `.acquire` method blocks if necessary until it can return without making the counter negative. - - `.acquire` supports the context manager protocol: - - >>> from tornado import gen, locks - >>> semaphore = locks.Semaphore() - >>> @gen.coroutine - ... def f(): - ... with (yield semaphore.acquire()): - ... # Do something holding the semaphore. - ... pass - ... - ... # Now the semaphore is released. """ def __init__(self, value=1): super(Semaphore, self).__init__()