tornado.locks – 同步原语¶
4.2 新版功能.
使用和标准库提供给线程相似的同步原语协调协程.
(请注意, 这些原语不是线程安全的, 不能被用来代替标准库中的–它 们是为了协调在单线程app中的Tornado协程, 而不是为了在一个多线程 app中保护共享对象.)
Condition¶
-
class
tornado.locks.Condition[源代码]¶ 允许一个或多个协程等待直到被通知的条件.
就像标准的
threading.Condition, 但是不需要一个被获取和释放的底层锁.通过
Condition, 协程可以等待着被其他协程通知: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有一个可选参数timeout, 要不然是一个绝对的时间戳:io_loop = IOLoop.current() # Wait up to 1 second for a notification. yield condition.wait(timeout=io_loop.time() + 1)
...或一个
datetime.timedelta相对于当前时间的一个延时:# Wait up to 1 second. yield condition.wait(timeout=datetime.timedelta(seconds=1))
这个方法将抛出一个
tornado.gen.TimeoutError如果在最后时间之前都 没有通知.
Event¶
-
class
tornado.locks.Event[源代码]¶ 一个阻塞协程的事件直到它的内部标识设置为True.
类似于
threading.Event.协程可以等待一个事件被设置. 一旦它被设置, 调用
yield event.wait()将不会被阻塞除非该事件已经被清除: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
-
wait(timeout=None)[源代码]¶ 阻塞直到内部标识为true.
返回一个Future对象, 在超时之后会抛出一个
tornado.gen.TimeoutError异常.
-
Semaphore¶
-
class
tornado.locks.Semaphore(value=1)[源代码]¶ 可以在阻塞之前获得固定次数的锁.
一个信号量管理着代表
release调用次数减去acquire的 调用次数的计数器, 加一个初始值. 如果必要的话,`.acquire` 方 法将会阻塞, 直到它可以返回, 而不使该计数器成为负值.信号量限制访问共享资源. 为了允许两个worker同时获得权限:
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 和 1 允许并行运行, 但是worker 2将等待直到 信号量被worker 0释放.
acquire是一个上下文管理器, 所以worker可以被写为:@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)
在 Python 3.5 中, 信号量自身可以作为一个异步上下文管理器:
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 版更改: 添加对 Python 3.5
async with的支持.-
acquire(timeout=None)[源代码]¶ 递减计数器. 返回一个 Future 对象.
如果计数器(counter)为0将会阻塞, 等待
release. 在超时之后 Future 对象将会抛出TimeoutError.
-
BoundedSemaphore¶
-
class
tornado.locks.BoundedSemaphore(value=1)[源代码]¶ 一个防止release() 被调用太多次的信号量.
如果
release增加信号量的值超过初始值, 它将抛出ValueError. 信号量通常是通过限制容量来保护资源, 所以一个信号量释放太多次是 一个错误的标志.-
acquire(timeout=None)¶ 递减计数器. 返回一个 Future 对象.
如果计数器(counter)为0将会阻塞, 等待
release. 在超时之后 Future 对象将会抛出TimeoutError.
-
Lock¶
-
class
tornado.locks.Lock[源代码]¶ 协程的锁.
一个Lock开始解锁, 然后它立即
acquire锁. 虽然它是锁着的, 一个协程yieldacquire并等待, 直到另一个协程调用release.释放一个没锁住的锁将抛出
RuntimeError.在所有Python 版本中
acquire支持上下文管理协议:>>> 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.
在Python 3.5,
Lock也支持异步上下文管理协议(async context manager protocol). 注意在这种情况下没有acquire, 因为async with同时包含yield和acquire(就像threading.Lock):>>> async def f(): ... async with lock: ... # Do something holding the lock. ... pass ... ... # Now the lock is released.
在 3.5 版更改: 添加Python 3.5 的
async with支持.-
acquire(timeout=None)[源代码]¶ 尝试锁. 返回一个Future 对象.
返回一个Future 对象, 在超时之后将抛出
tornado.gen.TimeoutError.
-
release()[源代码]¶ Unlock.
在队列中等待
acquire的第一个 coroutine 获得锁.如果没有锁, 将抛出
RuntimeError.
-