在我的应用程序中,我尝试创建一个将大文件流式传输到客户端的处理程序。这些文件由另一个模块(确切地说是tarfile
)创建。
我想要的是一个类似文件的对象,而不是写入磁盘上的套接字或实际文件,代替RequestHandler.write
方法。
这是我目前的天真实现:
import tornado.gen
import tornado.ioloop
import tornado.web
class HandlerFileObject(object):
def __init__(self, handler):
self.handler = handler
@tornado.gen.coroutine
def write(self, data):
self.handler.write(data)
yield self.handler.flush()
def close(self):
self.handler.finish()
class DownloadHandler(tornado.web.RequestHandler):
def get(self):
self.set_status(200)
self.set_header("Content-Type", "application/octet-stream")
fp = HandlerFileObject(self)
with open('/dev/zero', 'rb') as devzero:
for _ in range(100*1024):
fp.write(devzero.read(1024))
fp.close()
if __name__ == '__main__':
app = tornado.web.Application([
(r"/", DownloadHandler)
])
app.listen(8888)
tornado.ioloop.IOLoop.instance().start()
它可以工作,但问题是所有数据都被加载到RAM中,直到我停止应用程序才会释放。 什么是更好/更惯用/更有资源的方式来实现这个目标?
答案 0 :(得分:3)
get()
时, fp.write()
也需要成为协程并且会产生效果。通过编写协程,您可以使您的对象不像文件一样 - 大多数调用者只会忽略其返回值,屏蔽异常并干扰流控制。类文件接口是同步的,因此您可能需要在其他线程中执行这些操作,以便您可以根据需要阻止它们。