我有一个scikit-learn分类器作为Dockerized Flask应用程序运行,与gunicorn一起启动。它以 JSON 格式接收输入数据作为 POST 请求,并使用结果的 JSON 对象进行响应。
首次使用 gunicorn 启动应用时,将从数据库中读取一个大型模型(使用 joblib 序列化),并在应用准备好接受请求之前加载到内存中。这可能需要 10-15 分钟。
可重现的示例不可行,但基本结构如下所示:
from flask import Flask, jsonify, request, Response
import joblib
import json
def classifier_app(model_name):
# Line below takes 10-15 mins to complete
classifier = _load_model(model_name)
app = Flask(__name__)
@app.route('/classify_invoice', methods=['POST'])
def apicall():
query = request.get_json()
results = _build_results(query['data'])
return Response(response=results,
status=200,
mimetype='application/json')
print('App loaded!')
return app
如何配置 Flask 或 gunicorn 以在 _load_model
仍在运行时向任何传入的 http 请求返回"仍在加载"响应(或适当的错误消息)?
基本上,您希望为一个请求返回两个响应。所以有两种不同的可能性。
第一种是在后台运行耗时的任务,每两秒用简单的ajax请求ping服务器来检查任务是否完成。如果任务完成,则返回结果,如果没有,则返回"Please standby"
字符串或其他内容。
第二个是使用websockets和flask-socketio扩展。
基本服务器代码如下所示:
from threading import Thread
from flask import Flask
app = Flask(__name__)
socketio = SocketIO(app)
def do_work():
result = your_heavy_function()
socketio.emit("result", {"result": result}, namespace="/test/")
@app.route("/api/", methods=["POST"])
def start():
socketio.start_background_task(target=do_work)
# return intermediate response
return Response()
在客户端,你应该做这样的事情
var socket = io.connect('http://' + document.domain + ':' + location.port + '/test/');
socket.on('result', function(msg) {
// Process your request here
});
有关更多详细信息,请访问此博客文章,用于服务器端参考的 flask-socketio 文档和用于客户端参考的 socketio 文档。
PS 使用网络套接字,您也可以制作进度条。