Python Tornado对函数的异步调用

Python Tornado对函数的异步调用,python,class,function,asynchronous,tornado,Python,Class,Function,Asynchronous,Tornado,我正在使用Python+Tornado制作一个web应用程序,它基本上为用户提供文件。我没有数据库 如果文件可用,则直接获取并提供文件;如果不可用,则动态生成文件 我希望以异步方式为客户机提供服务,因为一些文件可能已经可用,而其他文件需要生成(因此它们需要等待,我不希望它们阻止其他用户) 我有一个类管理文件的拾取或生成,我只需要从Tornado调用它 实现这一点的最佳方法是什么(CPU和RAM效率最高)?我应该用线吗?一个子过程?一个简单的 另外,我希望我的实现能够在Google应用程序引擎上工

我正在使用Python+Tornado制作一个web应用程序,它基本上为用户提供文件。我没有数据库

如果文件可用,则直接获取并提供文件;如果不可用,则动态生成文件

我希望以异步方式为客户机提供服务,因为一些文件可能已经可用,而其他文件需要生成(因此它们需要等待,我不希望它们阻止其他用户)

我有一个类管理文件的拾取或生成,我只需要从Tornado调用它

实现这一点的最佳方法是什么(CPU和RAM效率最高)?我应该用线吗?一个子过程?一个简单的

另外,我希望我的实现能够在Google应用程序引擎上工作(我认为它们不允许生成子进程?)


我对异步web服务比较陌生,所以欢迎提供任何帮助。

我已经找到了问题的答案:genTask示例确实是实现异步调用的最佳方式,这是因为该示例确实使用了Python协程,我一眼就不明白,因为我认为收益率只用于为生成器返回一个值

具体例子:

class MyHandler(tornado.web.RequestHandler):

    @asynchronous
    @gen.engine
    def get(self):
        response = yield gen.Task(self.dosomething, 'argument')
import os.path
import tornado.web
from tornado import gen

class MyHandler(tornado.web.RequestHandler):

    @gen.coroutine
    def get(self, filename):
        result = yield self.some_usefull_process(filename)
        self.write(result)

    @gen.coroutine
    def some_usefull_process(self, filename):
        if not os.path.exists(filename):
            status = yield self.generate_file(filename)
            result = 'File created'
        else:
            result = 'File exists'

        raise gen.Return(result)

    @gen.coroutine
    def generate_file(self, filename):
        fd = open(filename, 'w')
        fd.write('created')
        fd.close()
这里重要的是两件事的结合:

  • 产生,这实际上产生了一个协同程序(或伪线程,它非常高效,并且非常适合并发)。

  • gen.Task()
    这是一个非阻塞(异步)函数,因为如果在阻塞函数上生成一个协程,它就不会是异步的<代码>gen.Task()由Tornado提供,专门用于使用Python的协同程序语法。更多资讯:

因此,Python中使用协同路由的异步调用的典型示例如下:

response = yield non_blocking_func(**kwargs)
现在有解决办法了

简单的例子:

class MyHandler(tornado.web.RequestHandler):

    @asynchronous
    @gen.engine
    def get(self):
        response = yield gen.Task(self.dosomething, 'argument')
import os.path
import tornado.web
from tornado import gen

class MyHandler(tornado.web.RequestHandler):

    @gen.coroutine
    def get(self, filename):
        result = yield self.some_usefull_process(filename)
        self.write(result)

    @gen.coroutine
    def some_usefull_process(self, filename):
        if not os.path.exists(filename):
            status = yield self.generate_file(filename)
            result = 'File created'
        else:
            result = 'File exists'

        raise gen.Return(result)

    @gen.coroutine
    def generate_file(self, filename):
        fd = open(filename, 'w')
        fd.write('created')
        fd.close()

将军的任务会很顺利的。如果您的文件获取/生成代码在这方面不能很好地发挥作用,那么线程将很好地工作。您也可以生成多个进程,但我不知道谷歌应用程序引擎的限制。感谢您的回复。你还知道如果我产生多个世代的任务,它将如何工作吗?我的意思是,我的实例方法可能非常耗费CPU和时间,如果这个方法被多个用户多次调用,会发生什么?所有方法是并行异步运行,还是下一个方法等待前一个方法首先终止?(请注意,我在整个应用程序中使用了我的类的一个实例)完全被屏蔽了,这应该是好的,但是不管您的解决方案如何,它都会成为一个有很多线程的问题。如果这是一个令人担忧的问题,可以尝试将其拆分为单独的进程或在负载平衡后运行多个实例。非常感谢Sean的回答。的确,我将在后台制作一个负载平衡器应用程序,在后台运行CPU繁重的任务,因此用户将始终拥有可用的文件。下面是另一篇文章,详细介绍了协同路由和旧回调实现: