Flask: 使用stream_with_context流传输文件非常慢

3
以下代码将Postgres BYTEA列流传输到浏览器。
from flask import Response, stream_with_context

@app.route('/api/1/zfile/<file_id>', methods=['GET'])
def download_file(file_id):

    file = ZFile.query.filter_by(id=file_id).first()
    return Response(stream_with_context(file.data), mimetype=file.mime_type)

下载速度极慢(大约5 MB需要6分钟)。

我正在使用curl从同一主机下载,因此网络不是问题, 而且我可以在不到一秒钟的时间内从psql控制台中提取文件, 因此似乎数据库方面也不应受到责备:

COPY (select f.data from z_file f where f.id = '4ec3rf') TO 'zazX.pdf' (FORMAT binary)

更新:

我有更多证据表明“从数据库获取数据”步骤并不慢。如果我使用

fs.writeFile()

file.data写入文件,则会发现这个操作比读取数据库更耗时。

with open("/vagrant/zoz.pdf", 'wb') as output:
    output.write(file.data)

同时,它只需要几分之一秒的时间。因此,Flask的流式传输方式导致了速度较慢。


你是否曾经想过如何提高Flask流媒体的性能?我也遇到了同样的问题。 - mdh
2个回答

7

我在使用Flask通过python-requests代理另一个网址进行流媒体传输时遇到了这个问题。

在这种情况下,技巧是在iter_content中设置chunk_size参数:

def flask_view():
    ...
    req = requests.get(url, stream=True, params=args)
    return Response(
        stream_with_context(req.iter_content(chunk_size=1024)),
        content_type=req.headers['content-type']

否则它将使用chunk_size = 1,这可能会使速度变慢。在我的情况下,增加chunk_size后,流式传输从几kb/s增加到了几mb/s。

1

Flask可以接收一个生成器,该生成器在单个yield中返回整个数组,并且“知道”如何处理它,这将在毫秒级别返回:

from flask import Response, stream_with_context

@app.route('/api/1/zfile/<file_id>', methods=['GET'])
def download_file(file_id):

    file = ZFile.query.filter_by(id=file_id).first()

    def single_chunk_generator():
        yield file.data

    return Response(stream_with_context(single_chunk_generator()), mimetype=file.mime_type)

stream_with_context函数,当传入一个数组时,会创建一个生成器来迭代数组中的每个元素,并对其进行各种检查,这将导致巨大的性能损失。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接