### Navigation
- [index](# "General Index")
- [modules](# "Python Module Index") |
- [next](# "tornado.queues – Queues for coroutines") |
- [previous](# "tornado.concurrent — Work with threads and futures") |
- [Tornado 4.4.dev1 documentation](#) »
- [Coroutines and concurrency](#) »
# `tornado.locks` – Synchronization primitives
New in version 4.2.
Coordinate coroutines with synchronization primitives analogous to those thestandard library provides to threads.
*(Note that these primitives are not actually thread-safe and cannot be used inplace of those from the standard library–they are meant to coordinate Tornadocoroutines in a single-threaded app, not to protect shared objects in amultithreaded app.)*
### Condition
*class *`tornado.locks.``Condition`[[source]](#)
A condition allows one or more coroutines to wait until notified.
Like a standard [`threading.Condition`](https://docs.python.org/3.4/library/threading.html#threading.Condition "(in Python v3.4)") [https://docs.python.org/3.4/library/threading.html#threading.Condition], but does not need an underlying lockthat is acquired and released.
With a [`Condition`](# "tornado.locks.Condition"), coroutines can wait to be notified by other coroutines:
~~~
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.locks import Condition
condition = 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()]
IOLoop.current().run_sync(runner)
~~~
~~~
I'll wait right here
About to notify
Done notifying
I'm done waiting
~~~
[`wait`](# "tornado.locks.Condition.wait") takes an optional `timeout` argument, which is either an absolutetimestamp:
~~~
io_loop = IOLoop.current()
# Wait up to 1 second for a notification.
yield condition.wait(timeout=io_loop.time() + 1)
~~~
...or a [`datetime.timedelta`](https://docs.python.org/3.4/library/datetime.html#datetime.timedelta "(in Python v3.4)") [https://docs.python.org/3.4/library/datetime.html#datetime.timedelta] for a timeout relative to the current time:
~~~
# Wait up to 1 second.
yield condition.wait(timeout=datetime.timedelta(seconds=1))
~~~
The method raises [`tornado.gen.TimeoutError`](# "tornado.gen.TimeoutError") if there's no notificationbefore the deadline.
`wait`(*timeout=None*)[[source]](#)
Wait for [`notify`](# "tornado.locks.Condition.notify").
Returns a [`Future`](# "tornado.concurrent.Future") that resolves `True` if the condition is notified,or `False` after a timeout.
`notify`(*n=1*)[[source]](#)
Wake `n` waiters.
`notify_all`()[[source]](#)
Wake all waiters.
### Event
*class *`tornado.locks.``Event`[[source]](#)
An event blocks coroutines until its internal flag is set to True.
Similar to [`threading.Event`](https://docs.python.org/3.4/library/threading.html#threading.Event "(in Python v3.4)") [https://docs.python.org/3.4/library/threading.html#threading.Event].
A coroutine can wait for an event to be set. Once it is set, calls to`yield event.wait()` will not block unless the event has been cleared:
~~~
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.locks import Event
event = Event()
@gen.coroutine
def waiter():
print("Waiting for event")
yield event.wait()
print("Not waiting this time")
yield event.wait()
print("Done")
@gen.coroutine
def setter():
print("About to set the event")
event.set()
@gen.coroutine
def runner():
yield [waiter(), setter()]
IOLoop.current().run_sync(runner)
~~~
~~~
Waiting for event
About to set the event
Not waiting this time
Done
~~~
`is_set`()[[source]](#)
Return `True` if the internal flag is true.
`set`()[[source]](#)
Set the internal flag to `True`. All waiters are awakened.
Calling [`wait`](# "tornado.locks.Event.wait") once the flag is set will not block.
`clear`()[[source]](#)
Reset the internal flag to `False`.
Calls to [`wait`](# "tornado.locks.Event.wait") will block until [`set`](# "tornado.locks.Event.set") is called.
`wait`(*timeout=None*)[[source]](#)
Block until the internal flag is true.
Returns a Future, which raises [`tornado.gen.TimeoutError`](# "tornado.gen.TimeoutError") after atimeout.
### Semaphore
*class *`tornado.locks.``Semaphore`(*value=1*)[[source]](#)
A lock that can be acquired a fixed number of times before blocking.
A Semaphore manages a counter representing the number of [`release`](# "tornado.locks.Semaphore.release") callsminus the number of [`acquire`](# "tornado.locks.Semaphore.acquire") calls, plus an initial value. The [`acquire`](# "tornado.locks.Semaphore.acquire")method blocks if necessary until it can return without making the counternegative.
Semaphores limit access to a shared resource. To allow access for twoworkers at a time:
~~~
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.locks import Semaphore
sem = 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)]
IOLoop.current().run_sync(runner)
~~~
~~~
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 untilthe semaphore has been released once, by worker 0.
[`acquire`](# "tornado.locks.Semaphore.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)
~~~
In Python 3.5, the semaphore itself can be used as an async contextmanager:
~~~
async def worker(worker_id):
async with sem:
print("Worker %d is working" % worker_id)
await use_some_resource()
# Now the semaphore has been released.
print("Worker %d is done" % worker_id)
~~~
Changed in version 4.3: Added `async with` support in Python 3.5.
`release`()[[source]](#)
Increment the counter and wake one waiter.
`acquire`(*timeout=None*)[[source]](#)
Decrement the counter. Returns a Future.
Block if the counter is zero and wait for a [`release`](# "tornado.locks.Semaphore.release"). The Futureraises [`TimeoutError`](# "tornado.gen.TimeoutError") after the deadline.
### BoundedSemaphore
*class *`tornado.locks.``BoundedSemaphore`(*value=1*)[[source]](#)
A semaphore that prevents release() being called too many times.
If [`release`](# "tornado.locks.BoundedSemaphore.release") would increment the semaphore's value past the initialvalue, it raises [`ValueError`](https://docs.python.org/3.4/library/exceptions.html#ValueError "(in Python v3.4)") [https://docs.python.org/3.4/library/exceptions.html#ValueError]. Semaphores are mostly used to guardresources with limited capacity, so a semaphore released too many timesis a sign of a bug.
`release`()[[source]](#)
Increment the counter and wake one waiter.
`acquire`(*timeout=None*)
Decrement the counter. Returns a Future.
Block if the counter is zero and wait for a [`release`](# "tornado.locks.BoundedSemaphore.release"). The Futureraises [`TimeoutError`](# "tornado.gen.TimeoutError") after the deadline.
### Lock
*class *`tornado.locks.``Lock`[[source]](#)
A lock for coroutines.
A Lock begins unlocked, and [`acquire`](# "tornado.locks.Lock.acquire") locks it immediately. While it islocked, a coroutine that yields [`acquire`](# "tornado.locks.Lock.acquire") waits until another coroutinecalls [`release`](# "tornado.locks.Lock.release").
Releasing an unlocked lock raises [`RuntimeError`](https://docs.python.org/3.4/library/exceptions.html#RuntimeError "(in Python v3.4)") [https://docs.python.org/3.4/library/exceptions.html#RuntimeError].
[`acquire`](# "tornado.locks.Lock.acquire") supports the context manager protocol in all Python versions:
~~~
>>> from tornado import gen, locks
>>> lock = locks.Lock()
>>>
>>> @gen.coroutine
... def f():
... with (yield lock.acquire()):
... # Do something holding the lock.
... pass
...
... # Now the lock is released.
~~~
In Python 3.5, [`Lock`](# "tornado.locks.Lock") also supports the async context managerprotocol. Note that in this case there is no [`acquire`](# "tornado.locks.Lock.acquire"), because`async with` includes both the `yield` and the `acquire`(just as it does with [`threading.Lock`](https://docs.python.org/3.4/library/threading.html#threading.Lock "(in Python v3.4)") [https://docs.python.org/3.4/library/threading.html#threading.Lock]):
~~~
>>> async def f():
... async with lock:
... # Do something holding the lock.
... pass
...
... # Now the lock is released.
~~~
Changed in version 4.3: Added `async with` support in Python 3.5.
`acquire`(*timeout=None*)[[source]](#)
Attempt to lock. Returns a Future.
Returns a Future, which raises [`tornado.gen.TimeoutError`](# "tornado.gen.TimeoutError") after atimeout.
`release`()[[source]](#)
Unlock.
The first coroutine in line waiting for [`acquire`](# "tornado.locks.Lock.acquire") gets the lock.
If not locked, raise a [`RuntimeError`](https://docs.python.org/3.4/library/exceptions.html#RuntimeError "(in Python v3.4)") [https://docs.python.org/3.4/library/exceptions.html#RuntimeError].
© Copyright 2009-2016, The Tornado Authors. Created using [Sphinx](http://sphinx-doc.org/) 1.3.5.
- User's guide
- Introduction
- Asynchronous and non-Blocking I/O
- Coroutines
- Queue example - a concurrent web spider
- Structure of a Tornado web application
- Templates and UI
- Authentication and security
- Running and deploying
- Web framework
- tornado.web — RequestHandler and Application classes
- tornado.template — Flexible output generation
- tornado.escape — Escaping and string manipulation
- tornado.locale — Internationalization support
- tornado.websocket — Bidirectional communication to the browser
- HTTP servers and clients
- tornado.httpserver — Non-blocking HTTP server
- tornado.httpclient — Asynchronous HTTP client
- tornado.httputil — Manipulate HTTP headers and URLs
- tornado.http1connection – HTTP/1.x client/server implementation
- Asynchronous networking
- tornado.ioloop — Main event loop
- tornado.iostream — Convenient wrappers for non-blocking sockets
- tornado.netutil — Miscellaneous network utilities
- tornado.tcpclient — IOStream connection factory
- tornado.tcpserver — Basic IOStream-based TCP server
- Coroutines and concurrency
- tornado.gen — Simplify asynchronous code
- tornado.concurrent — Work with threads and futures
- tornado.locks – Synchronization primitives
- tornado.queues – Queues for coroutines
- tornado.process — Utilities for multiple processes
- Integration with other services
- tornado.auth — Third-party login with OpenID and OAuth
- tornado.wsgi — Interoperability with other Python frameworks and servers
- tornado.platform.asyncio — Bridge between asyncio and Tornado
- tornado.platform.caresresolver — Asynchronous DNS Resolver using C-Ares
- tornado.platform.twisted — Bridges between Twisted and Tornado
- Utilities
- tornado.autoreload — Automatically detect code changes in development
- tornado.log — Logging support
- tornado.options — Command-line parsing
- tornado.stack_context — Exception handling across asynchronous callbacks
- tornado.testing — Unit testing support for asynchronous code
- tornado.util — General-purpose utilities
- Frequently Asked Questions
- Release notes
- What's new in Tornado 4.3
- What's new in Tornado 4.2.1
- What's new in Tornado 4.2
- What's new in Tornado 4.1
- What's new in Tornado 4.0.2
- What's new in Tornado 4.0.1
- What's new in Tornado 4.0
- What's new in Tornado 3.2.2
- What's new in Tornado 3.2.1
- What's new in Tornado 3.2
- What's new in Tornado 3.1.1
- What's new in Tornado 3.1
- What's new in Tornado 3.0.2
- What's new in Tornado 3.0.1
- What's new in Tornado 3.0
- What's new in Tornado 2.4.1
- What's new in Tornado 2.4
- What's new in Tornado 2.3
- What's new in Tornado 2.2.1
- What's new in Tornado 2.2
- What's new in Tornado 2.1.1
- What's new in Tornado 2.1
- What's new in Tornado 2.0
- What's new in Tornado 1.2.1
- What's new in Tornado 1.2
- What's new in Tornado 1.1.1
- What's new in Tornado 1.1
- What's new in Tornado 1.0.1
- What's new in Tornado 1.0