tornado.locks – Synchronization primitives¶
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
[源代码]¶
A condition allows one or more coroutines to wait until notified.
Like a standardthreading.Condition
, but does not need an underlying lockthat is acquired and released.
With aCondition
, 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().runsync(runner)
- I'll wait right here
About to notify
Done notifying
I'm done waiting
wait
takes an optionaltimeout
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 adatetime.timedelta
for a timeout relative to the current time:- # Wait up to 1 second.
yield condition.wait(timeout=datetime.timedelta(seconds=1))
The method raisestornado.gen.TimeoutError
if there’s no notificationbefore the deadline.- from tornado import gen
Event¶
- class
tornado.locks.
Event
[源代码]¶
An event blocks coroutines until its internal flag is set to True.
Similar tothreading.Event
.
A coroutine can wait for an event to be set. Once it is set, calls toyield 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().runsync(runner)
- Waiting for event
About to set the event
Not waiting this time
Done
set
()[源代码]¶
Set the internal flag toTrue
. All waiters are awakened.
Callingwait
once the flag is set will not block.
wait
(_timeout=None)[源代码]¶
Block until the internal flag is true.
Returns a Future, which raisestornado.gen.TimeoutError
after atimeout.
- from tornado import gen
Semaphore¶
- class
tornado.locks.
Semaphore
(value=1)[源代码]¶
A lock that can be acquired a fixed number of times before blocking.
A Semaphore manages a counter representing the number ofrelease
callsminus the number ofacquire
calls, plus an initial value. Theacquire
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(workerid):
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
is a context manager, soworker
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)
在 4.3 版更改: Addedasync with
support in Python 3.5.acquire
(_timeout=None)[源代码]¶
Decrement the counter. Returns a Future.
Block if the counter is zero and wait for arelease
. The FutureraisesTimeoutError
after the deadline.
- from tornado import gen
BoundedSemaphore¶
- class
tornado.locks.
BoundedSemaphore
(value=1)[源代码]¶
A semaphore that prevents release() being called too many times.
Ifrelease
would increment the semaphore’s value past the initialvalue, it raisesValueError
. Semaphores are mostly used to guardresources with limited capacity, so a semaphore released too many timesis a sign of a bug.acquire
(timeout=None)¶
Decrement the counter. Returns a Future.
Block if the counter is zero and wait for arelease
. The FutureraisesTimeoutError
after the deadline.
Lock¶
- class
tornado.locks.
Lock
[源代码]¶
A lock for coroutines.
A Lock begins unlocked, andacquire
locks it immediately. While it islocked, a coroutine that yieldsacquire
waits until another coroutinecallsrelease
.
Releasing an unlocked lock raisesRuntimeError
.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
also supports the async context managerprotocol. Note that in this case there is noacquire
, becauseasync with
includes both theyield
and theacquire
(just as it does withthreading.Lock
):- >>> async def f():
… async with lock:
… # Do something holding the lock.
… pass
…
… # Now the lock is released.
在 4.3 版更改: Addedasync with
support in Python 3.5.acquire
(timeout=None)[源代码]¶
Attempt to lock. Returns a Future.
Returns a Future, which raisestornado.gen.TimeoutError
after atimeout.
release
()[源代码]¶
Unlock.
The first coroutine in line waiting foracquire
gets the lock.
If not locked, raise aRuntimeError
.
- >>> from tornado import gen, locks
原文:
https://tornado-zh-cn.readthedocs.io/zh_CN/latest/locks.html