Skip to main content

tornado.locks - 同步原语

4.2 新版功能.

协调程序与类似于标准库提供给线程的同步原语。

(请注意,这些原语实际上不是线程安全的,不能用来代替标准库中的那些 - 它们用于在单线程应用程序中协调Tornado协程,而不是保护多线程应用程序中的共享对象。)

条件

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

wait(timeout=None)[源代码]

等待 notify

返回 Future,如果通知条件,则 Future 解析 True,或在超时后返回 False

notify(n=1)[源代码]

唤醒 n 服务员。

notify_all()[源代码]

唤醒所有服务员。

事件

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
is_set()[源代码]

如果内部标志为真,则返回 True

set()[源代码]

将内部标志设置为 True。所有的服务员都被唤醒。

标志置位后调用 wait 不会阻塞。

clear()[源代码]

将内部标志重置为 False

wait 的调用将阻塞,直到 set 被调用。

wait(timeout=None)[源代码]

阻塞直到内部标志为真。

返回一个未来,它在超时后引发 tornado.gen.TimeoutError

信号

class tornado.locks.Semaphore(value=1)[源代码]

在锁定之前可以获取固定次数的锁。

信号量管理一个表示 release 呼叫数量减去 acquire 呼叫数量加上一个初始值的计数器。如果需要,acquire 方法阻塞,直到它可以返回而不使计数器为负。

信号量限制对共享资源的访问。允许一次访问两个工人:

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

工作器0和1允许同时运行,但工作器2等待,直到信号量被工作器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 支持。

release()[源代码]

递增计数器并唤醒一个服务员。

acquire(timeout=None)[源代码]

递减计数器。返回未来。

如果计数器为零并等待 release,则阻塞。未来在截止日期之后提高 TimeoutError

BoundedSemaphore

class tornado.locks.BoundedSemaphore(value=1)[源代码]

防止release()被调用次数过多的信号量。

如果 release 将信号量的值增加超过初始值,则它提高 ValueError。信号量主要用于保护有限容量的资源,因此信号量释放太多次是一个错误的迹象。

release()[源代码]

递增计数器并唤醒一个服务员。

acquire(timeout=None)

递减计数器。返回未来。

如果计数器为零并等待 release,则阻塞。未来在截止日期之后提高 TimeoutError

class tornado.locks.Lock[源代码]

协同锁。

锁开始解锁,acquire 立即锁定。当它被锁定时,产生 acquire 的协同程序等待,直到另一个协同程序调用 release

释放解锁的锁提高 RuntimeError

acquire 在所有Python版本中支持上下文管理器协议:

>>> 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 还支持异步上下文管理器协议。注意,在这种情况下没有 acquire,因为 async with 包括 yieldacquire (正如它与 threading.Lock 一样):

>>> async def f():  
...    async with lock:
...        # Do something holding the lock.
...        pass
...
...    # Now the lock is released.

在 4.3 版更改: 在Python 3.5中添加了 async with 支持。

acquire(timeout=None)[源代码]

尝试锁定。返回未来。

返回一个未来,它在超时后引发 tornado.gen.TimeoutError

release()[源代码]

开锁。

第一个在线等待 acquire 的协程获取锁。

如果未锁定,请提出 RuntimeError