我正在使用Python + Tornado创建一个Web应用程序,它基本上为用户提供文件。我没有数据库。
如果文件可用,则直接提取和提供文件,否则即时生成文件。
我希望以异步方式提供客户端,因为某些文件可能已经可用,而其他文件需要生成(因此需要等待,我不希望它们阻止其他用户)。 / p>
我有一个管理文件拣选或生成的类,我只需要从Tornado调用它。
实现这一目标的最佳方法(在CPU和RAM上效率最高)是什么?我应该使用线程吗?一个子流程?一个简单的gen.Task like this one?
另外,我希望我的实现能够在Google App Engines上运行(我认为它们不允许生成子流程吗?)。
我对异步网络服务相对较新,所以欢迎任何帮助。
答案 0 :(得分:10)
我找到了我的问题的答案:genTask示例确实是实现异步调用的最佳方式,这是因为该示例确实使用了 Python协程,我乍一看并不明白,因为我认为 yield 仅用于返回生成器的值。
具体例子:
class MyHandler(tornado.web.RequestHandler):
@asynchronous
@gen.engine
def get(self):
response = yield gen.Task(self.dosomething, 'argument')
这里重要的是两件事的组合:
yield ,实际上产生了一个协同程序(或伪线程,这是非常有效的,并且是高度并发友好的)。 http://www.python.org/dev/peps/pep-0342/
gen.Task()
这是一个非阻塞(异步)函数,因为如果你在一个阻塞函数上产生一个协同程序,它就不会是异步的。 gen.Task()
由Tornado提供,专门用于处理Python的协程语法。更多信息:
http://www.tornadoweb.org/documentation/gen.html
这是使用协同程序在Python中进行异步调用的典型示例:
response = yield non_blocking_func(**kwargs)
答案 1 :(得分:1)
现在Documentation有解决方案。
简单示例:
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()