自定义装饰器中的Tornado异步操作

时间:2017-10-30 08:25:38

标签: python tornado decorator coroutine

我正在尝试使用redis和tornadis库为我的Tornado路由处理程序构建一个缓存装饰器。 这就是我到目前为止所做的:

def rediscache(route):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            result = yield redis.call("GET", "latest_info")
            print(result)
            func(*args, **kwargs)
        return wrapper
    return decorator

在我的路由处理程序中,我正在使用它:

class MainHandler(tornado.web.RequestHandler):

    def initialize(self, db, redis):
        self.db = db
        self.quakes = self.db.quakes
        self.redis = redis

    @gen.coroutine
    @rediscache('route_is_here')
    def get(self):
        ''' ... handler logic here ... '''

问题是,如果我使用装饰器,我会停止从我的处理程序看到输出到网络。如果不是......

result = yield redis.call("GET", "latest_info")

我做......

result = redis.call("GET", "latest_info")

然后我再次开始在浏览器中看到输出,但这是正确的方法吗?这仍然是异步的吗?如果不是什么方式做到这一点?谢谢!

1 个答案:

答案 0 :(得分:2)

如果你想要gen.coroutine协同程序,装扮器中的包装器应为yield

def rediscache(route):
    def decorator(func):
        @tornado.gen.coroutine
        @wraps(func)
        def wrapper(*args, **kwargs):
            result = yield redis.call("GET", "latest_info")
            print(result)
            if not result:
                new = yield func(*args, **kwargs)
                # save to
        return wrapper
    return decorator

您还需要将装饰器的顺序更改为:

@rediscache('route_is_here')
@gen.coroutine
def get(self):
    ''' ... handler logic here ... '''

修改

装饰者命令的说明

@second
@first
def my_func():
    pass

相同
my_func = second(first(my_func))

因此,如果您想在装饰器中等待(产生)原始get,则必须通过协同程序,因此它必须在rediscache之前。

有关装饰器的更多信息 - https://wiki.python.org/moin/PythonDecorators