首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >python-socketio在flask服务器上跟踪文件下载时并不总是发出

python-socketio在flask服务器上跟踪文件下载时并不总是发出
EN

Stack Overflow用户
提问于 2018-07-18 03:56:05
回答 1查看 499关注 0票数 0

我使用RESTful web服务的flask服务器和python-socketio来实现服务器和客户端之间的双向通信,以跟踪后端的下载进度。

我接受在server.py文件中声明的变量sio,并将其作为参数传递给一个新对象,该对象将使用它向客户端发送有关它的某些消息,该消息将随着在服务器上下载文件而进行。

代码语言:javascript
复制
sio = socketio.Server(async_mode='threading')
omics_env = None

@sio.on('init', namespace='/guardiome')
def init(sid, data):
    global omics_env

    if omics_env == None:
        omics_env = Environment(socket=sio)
        omics_env.conda.download_conda()
        omics_env.data_management.download_omics_data()

问题是,当文件在python服务器中下载时,每次向文件写入1%的数据时,它都会向客户端发送一条消息。但它并不总是在每次下载/写入1%的数据到文件时都发送给客户端。

它通常会报告进度到18%,推迟一段时间,然后报告40%,跳过18%到40%之间的排放。

有些人可能会说这可能是互联网的滞后,但我确实在emit函数的顶部打印了download函数中的语句,该函数显示它正在写入/下载每1%的数据。

我也在网上查过其他的资源。有些人提到使用eventlet,并在服务器的最高代码级别做类似的事情。

代码语言:javascript
复制
import eventlet
evenlet.monkey_patch()

但这根本不会导致代码发出。

其他人提到使用像redis这样的消息队列,但我不能使用redis,我计划将整个python代码转换为二进制可执行文件,以便它在linux平台上完全可移植,以便与本地客户端进行通信。

这是我的server.py

代码语言:javascript
复制
import socketio
import eventlet.wsgi

from environment import Environment

from flask import Flask, jsonify, request, send_file
from flask_cors import CORS

omics_env = None

sio = socketio.Server(async_mode='threading')
app = Flask(__name__)
CORS(app)

@sio.on('init', namespace='/guardiome')
def init(sid, data):
    global omics_env

    if omics_env == None:
        omics_env = Environment(socket=sio)
        omics_env.conda.download_conda()
        omics_env.data_management.download_omics_data()

    omics_env.logger.info('_is_ready()')

    sio.emit(
        event='init',
        data={'status': True, 'information': None},
        namespace='/guardiome')


try:
    # wrap Flask application with engineio's middleware
    app.wsgi_app = socketio.Middleware(sio, app.wsgi_app)
    # Launch the server with socket integration
    app.run(port=8008, debug=False, threaded=True)

finally:
    pass
    # LOGGER.info('Exiting ...')

下面是我将sio作为报告器参数传入的download_w_progress函数

代码语言:javascript
复制
def download_w_progress(url , path, reporter=None):

    ssl._create_default_https_context = ssl._create_unverified_context
    r = requests.get(url, stream=True)

    # Helper lambda functions
    progress_report = lambda current, total: int((current/total)*100)
    raw_percent = lambda current, total: (current/total)*100

    # TODO(mak3): Write lambda function for reporting amount of file downloaded
    # in MB, KB, GB, or whatever

    with open(path, 'wb') as f:

        total_length = int(r.headers.get('content-length'))
        progress_count = 0
        chunk_size = 1024

        # Used to cut down on emit the same rounded percentage number
        previous_percent = -1

        # Read and write the file in chunks to its destination
        for chunk in r.iter_content(chunk_size=1024):
            progress_dict = {
                "percent": progress_report(progress_count, total_length)
            }

            if reporter != None:
                # Limit the number of emits sent to prevent
                # to socket from overworking
                if progress_dict["percent"] != previous_percent:
                    reporter.emit(event="environment", namespace="/guardiome", data=progress_dict)


            # TODO(mak3): Remove or uncomment in production
            if progress_dict["percent"] != previous_percent:
                print(progress_dict["percent"], end='\r')

            progress_count += chunk_size
            previous_percent = progress_dict["percent"]

            if chunk:
                f.write(chunk)
                f.flush()
EN

回答 1

Stack Overflow用户

发布于 2019-03-15 19:54:52

很抱歉,当你发布这个问题时,我错过了它。

你的代码中有几个问题。您正在选择async_mode='threading。通常,最好忽略此参数,让服务器根据您使用的服务器选择最佳的异步模式。例如,当您添加eventlet时,线程模式将不起作用,实际上eventlet有一个特定的异步模式。

所以我的建议是:

使用启动eventlet服务器的代码删除脚本中虚拟constructor

  • install environment

  • replace app.run()部分中的Flask
  1. eventlet中的async_mode参数,或使用Flask-SocketIO扩展,该扩展已经内置了此代码。
  2. 在读取文件的循环中添加sio.sleep(0)调用。这将使eventlet有机会保持所有任务顺利运行。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51389291

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档