从 @web.asynchronous 到 @gen.coroutine 的 Tornado Web 应用程序转换

在 Tornado Web 框架中,我想将当前使用 @web.asynchronous 装饰器的应用程序转换到 @gen.coroutine 装饰器。我的异步回调函数在一个 IOLoop 迭代中调用特定变量更改时执行。Tornado 文档中的示例是为了解决 I/O 问题,但在我的例子中,我感兴趣的是变量本身。我希望在变量更改时唤醒协程。我的应用程序如下所示:

# 一个事务代表可能由另一个进程触发的数据库变更
class Transaction:
    def __init__(self):
        self.status = 'INCOMPLETE'
        self.callback = None

# 在这里,在做出 GET 请求响应之前,我正在检查数据库的状态
class MainHandler(web.RequestHandler):
    def initialize(self, app_reference):
        self.app_reference = app_reference

    @web.asynchronous
    def get(self):
        txn = Transaction()
        callback = functools.partial(self.do_something)
        txn.callback = callback

        self.app_reference.monitor_transaction(txn)

    def do_something(self):
        self.write("Finished GET request")
        self.finish()

# MyApp 监控事务列表,并在事务状态变为“已完成”状态时添加回调函数“transaction.callback”。
class MyApp(Application):
    def __init__(self, settings):
        self.settings = settings
        self._url_patterns = self._get_url_patterns()
        self.txn_list = [] # 正在监控的所有事务的列表
        Application.__init__(self, self._url_patterns, **self.settings)
        IOLoop.current().add_callback(self.check_status)

    def monitor_transaction(self, txn):
        self.txn_list.append(txn)

    def check_status(self):
        count = 0
        for transaction in self.txn_list:
            transaction.status = is_transaction_complete()
            if transaction.status is 'COMPLETE':
                IOLoop.current().add_callback(transaction.callback)
                self.txn_list.pop(count)
            count += 1
        if len(self.txn_list):
            IOloop.current().add_callback(self.check_status)

    # 向 url_patterns 中添加 'self'
    def _get_url_patterns(self):
        from urls import url_patterns
        modified_url_patterns = []
        for url in url_patterns:
            modified_url_patterns.append( url + ({ 'app_reference': self },))
        return modified_url_patterns

如果我理解正确,为了使用 gen.coroutine 装饰器进行编写,get 方法应该修改如下:

@gen.coroutine
def get(self):
    txn = Transaction()
    response = yield wake_up_when_transaction_completes()
    # 在此做出 GET 响应

我的问题在于,我不确定如何仅在状态更改时唤醒一个例程,我不能使用一个循环,因为它会阻塞 Tornado 线程。基本上,我想在 IOLoop 迭代时通知例程。

def check_status():
    for transaction in txn_list:
        if transaction.status is 'COMPLETE':
            NOTIFY_COROUTINE

2、解决方案

您可以使用 Tornado 4.2 版本中引入的新 tornado.locks 模块来解决这个问题。根据您的描述,您可以使用 Event 类来实现此目的:

from tornado import locks, gen

event = locks.Event()

@gen.coroutine
def waiter():
    print("Waiting for event")
    yield event.wait()
    print("Done")

@gen.coroutine
def setter():
    print("About to set the event")
    event.set()

在您的代码中,您可以使用如下方式唤醒您的协程:

@gen.coroutine
def get(self):
    txn = Transaction()
    event = locks.Event()
    txn.callback = event.set
    self.app_reference.monitor_transaction(txn)
    yield event.wait()
    # 在此做出 GET 响应

这样,当事务完成时,event.set() 会被调用,从而唤醒协程并继续执行 get 方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值