我有现有的代码将数据序列化为类似文件的对象:
def some_serialization_function(file):
file.write(...)
在Flask中,我希望能够将序列化数据直接发送到客户端, 不先在内存中缓冲它。
我查看了来自werkzeug的ResponseStreamMixin,但我认为它可以在没有缓冲的情况下工作:
class StreamResponse(flask.Response, werkzeug.wrappers.ResponseStreamMixin):
pass
@app.route("/data")
def get_data():
r = StreamResponse()
some_serialization_function(r.stream) # everything is buffered into memory
return r # buffered data is sent after return
我发现的流数据的所有示例都是基于生成器,它们在相反的方向上工作(即数据是"从发生器拉出#34;而不是"推出"通过a写电话),所以我想,是有一种方法可以#34;写"直接给Flask的客户?
编辑 - 更清楚:我正在寻找一种方法来提供由" some_serialization_function(...)"生成的数据。 (我不能轻易改变)没有使用该函数的内存/ IO开销首先将所有数据写入缓冲区/文件。
(我怀疑临时文件将是最终的方式,因为与通过网络实际发送数据的开销相比,IO开销不会很大。此外,我主要担心的是内存开销)。
答案 0 :(得分:4)
您可以创建一个特殊的类文件对象,该对象将流式传输到客户端的生成器。这是一个快速的&使用队列的脏实现:
from queue import Queue
class StreamWriter(object):
def __init__(self):
self.queue = Queue()
def write(self, str):
self.queue.put(str)
def read(self):
str = self.queue.get()
self.queue.task_done()
if str == '~':
return None
return str
def close(self):
self.write('~') # indicate EOF
这只不过是pub-sub类型的队列。 read()
方法将阻塞,直到在另一个线程中写入内容。
现在您可以使用生成器传输响应。以下示例显示了将序列化函数作为参数的生成器。序列化函数在后台线程中执行,并接收类文件对象作为参数。
def generate_response(serialize):
file = StreamWriter()
def serialize_task():
serialize(file)
file.close()
threading.Thread(target=serialize_task).start()
while True:
chunk = file.read()
if chunk is None:
break
yield chunk
我希望这有帮助!
答案 1 :(得分:-1)
如果我理解你,你想要
write
应用程序。我认为,由于某人必须控制流量,因此无法完成此操作。如果是网络应用,则客户端正在读取数据。
另一方面,如果您希望阻止缓存整个内容在Web应用程序上提供给客户端,您可以逐个读取Web服务器上的数据并逐个产生。
from flask import Flask, Response, request
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route('/loop')
def loop():
def generate():
yield "Hello"
yield "World"
return Response(generate())
@app.route('/longloop/<int:rows>')
def longloop(rows):
def generate(rows):
for i in xrange(rows):
yield "{i}: Hello World".format(i=i)
return Response(generate(rows))
if __name__ == '__main__':
app.run(debug=True)
诀窍是使用Response
对象和生成器生成输出。
如果您访问http://localhost:5000/longloop/100
,您将收到100个问候语。
使用curl
从命令行尝试此操作,并更好地将输出重定向到/dev/null
:
$ curl -X GET http://localhost:5000/longloop/120000000 > /dev/null
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 538M 0 538M 0 0 1056k 0 --:--:-- 0:08:41 --:--:-- 1079k
正如我们所看到的,脚本现在运行超过8分钟,烧瓶app消耗的内存大致相同,在我的情况下,它保持在总RAM的0.4%。