Flask:通过写入客户端流数据?

hmn*_*hmn 3 python werkzeug flask

我有一些将数据序列化为类似文件的对象的代码:

def some_serialization_function(file):
    file.write(...)
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

我发现的所有流数据示例都是基于生成器的,它们的工作方向相反(即,数据是从生成器中“拉出”的,而不是通过写调用“推出”的),所以我想知道是否有一种方法可以直接在Flask中“写”给客户端?

编辑-更清楚地说:我正在寻找一种方法来处理“ some_serialization_function(...)”(我不容易更改)生成的数据,而又不会使该函数将所有数据写入到内存/ IO开销中缓冲区/文件优先。

(我怀疑临时文件将是最终的解决方法,因为与通过网络实际发送数据的开销相比,IO开销并不重要。我主要关心的是内存开销)。

Mig*_*uel 5

您可以创建一个类似于文件的特殊对象,该对象将生成器馈入并流式传输到客户端。这是使用队列的快速而肮脏的实现:

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
Run Code Online (Sandbox Code Playgroud)

这不过是发布订阅类型队列。该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
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助!