本文介绍了在 Tornado 中缓存和重用函数结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 Tornado 应用程序中包含一个昂贵的函数.功能返回几个输出,但由于遗留原因,这些输出被访问分别通过不同的处理程序.

I have an expensive function to include in my Tornado app. The functionreturns several outputs but, for legacy reason, these outputs are accessedseparately through different handlers.

有没有办法只执行一次函数,将结果重新用于不同的处理程序并保留 Tornado 的异步行为?

Is there a way to execute the function only once, re-use the result for thedifferent handlers and preserve Tornado's asynchronous behavior?

from tornado.web import RequestHandler
from tonado.ioloop import IOLoop

# the expensive function
def add(x, y):
    z = x + y
    return x, y, z

# the handlers that reuse the function
class Get_X(RequestHandler):
    def get(self, x, y):
        x, y, z = add(x, y)
        return x

class Get_Y(RequestHandler):
    def get(self, x, y):
        x, y, z = add(x, y)
        return y

class Get_Z(RequestHandler):
    def get(self, x, y):
        x, y, z = add(x, y)
        return z

# the web service
application = tornado.web.Application([
    (r'/Get_X', Get_X),
    (r'/Get_Y', Get_Y),
    (r'/Get_Z', Get_Z),
])

application.listen(8888)
IOLoop.current().start()

我考虑过将函数的结果缓存在字典中,但我不确定如何让其他两个处理程序等待,而第一个处理程序创建一个字典条目.

I thought about about caching the result of the function in a dictionary, but I'm not sure on how to make the two other handlers wait, while the first one creates a dictionary entry.

推荐答案

Tornado Futures 是可重复使用的,因此您可以在生成它之前简单地保存 Future.许多现成的缓存装饰器(如 python 3.2 的 functools.lru_cache 就可以工作,如果你把它们放在 @gen.coroutine 的前面:

Tornado Futures are reusable, so you can simply save the Future before yielding it. Many off-the-shelf caching decorators (like python 3.2's functools.lru_cache will just work if you put them in front of @gen.coroutine:

import functools
from tornado import gen
from tornado.ioloop import IOLoop

@functools.lru_cache(maxsize=100)
@gen.coroutine
def expensive_function():
    print('starting expensive_function')
    yield gen.sleep(5)
    return 1, 2, 3

@gen.coroutine
def get_x():
    print('starting get_x')
    x, y, z = yield expensive_function()
    return x

@gen.coroutine
def get_y():
    print('starting get_y')
    x, y, z = yield expensive_function()
    return y

@gen.coroutine
def get_z():
    print('starting get_z')
    x, y, z = yield expensive_function()
    return z

@gen.coroutine
def main():
    x, y, z = yield [get_x(), get_y(), get_z()]
    print(x, y, z)

if __name__ == '__main__':
    IOLoop.current().run_sync(main)

打印:

starting get_x
starting expensive_function
starting get_y
starting get_z
finished expensive_function
1 2 3

这篇关于在 Tornado 中缓存和重用函数结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 11:20
查看更多