我使用RESTful web服务的flask服务器和python-socketio来实现服务器和客户端之间的双向通信,以跟踪后端的下载进度。
我接受在server.py文件中声明的变量sio,并将其作为参数传递给一个新对象,该对象将使用它向客户端发送有关它的某些消息,该消息将随着在服务器上下载文件而进行。
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,并在服务器的最高代码级别做类似的事情。
import eventlet
evenlet.monkey_patch()但这根本不会导致代码发出。
其他人提到使用像redis这样的消息队列,但我不能使用redis,我计划将整个python代码转换为二进制可执行文件,以便它在linux平台上完全可移植,以便与本地客户端进行通信。
这是我的server.py
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函数
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()发布于 2019-03-15 19:54:52
很抱歉,当你发布这个问题时,我错过了它。
你的代码中有几个问题。您正在选择async_mode='threading。通常,最好忽略此参数,让服务器根据您使用的服务器选择最佳的异步模式。例如,当您添加eventlet时,线程模式将不起作用,实际上eventlet有一个特定的异步模式。
所以我的建议是:
使用启动eventlet服务器的代码删除脚本中虚拟constructor
app.run()部分中的Flask async_mode参数,或使用Flask-SocketIO扩展,该扩展已经内置了此代码。sio.sleep(0)调用。这将使eventlet有机会保持所有任务顺利运行。https://stackoverflow.com/questions/51389291
复制相似问题