在使用Flask开发python的web应用时,可能会遇到需要较长时间处理的任务,此时就需要使用异步的方式来实现,让长时间任务在后台运行,先将本次请求的响应状态返回给前端,不然前端界面"卡顿",当异步任务处理好后,如果需要返回状态,再将状态返回。
下面介绍两种常用的方式:
(1)使用线程的方式
当要执行耗时任务时,直接开启一个新的线程来执行任务,这种方式最为简单快速。
通过ThreadPoolExecutor来实现
asyn_request_demo.py
# -*- coding: UTF-8 -*-
"""
# rs
"""
from logzero import logger
import time
from flask import Flask
from flask_restful import Api
from flask import jsonify
from flask import make_response
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor()
# executor = ThreadPoolExecutor(10) 里面的数字是线程池所能同时进行的最大数量
app = Flask(__name__)
api = Api(app)
def run(name, age):
"""
# 异步任务
"""
time.sleep(3)
logger.info("name: %s, age: %s." % (name, age))
logger.info("耗时任务执行结束")
@app.route('/test')
def test():
# 传递多个参数
args = ["rongsong", "28"]
# 交给线程去处理耗时任务, 异步执行
executor.submit(lambda p: run(*p), args)
# 直接返回结果
result = {
"code": "200",
"message": "success",
"data": "green"
}
return make_response(jsonify(result))
if __name__ == "__main__":
# 启动一个HTTP服务
app.run(host="0.0.0.0", port=8800, debug=True)
- 使用pip3安装相应的库(不再赘述)。
- 使用python3 asyn_request_demo.py运行启动即可(启动端口8800,可修改)。
- 然后访问http://{执行机器所在IP}:8800/test观察。
- 预期可以看到:接口直接返回result结果(同步),后台日志等待5s左右打印日志"耗时任务执行结束"(异步)。
当要执行一些比较简单的耗时任务时可以使用这种方式,如发邮件、发送短信验证码等。
当这种方式有个很明显的问题,就是我们无法得到任务的执行状态。
如果想要随时得到任务的执行状态,就需要设计一些逻辑,比如奖任务执行状态存储到Redis中,通过唯一的任务id进行标识,然后再写一个接口通过任务id去获取任务的状态,然后让前端定时的去请求该接口,从而获得任务状态信息。
是不是有点复杂,如果让我们自己实现的话,哈哈哈,别慌,Celery框架刚好实现了这样的逻辑,比较成熟,一般我们遇到问题时都可以先看看有没有现成的框架和方法,毕竟站在巨人的肩膀上我们可以看的更远。
(2)使用Celery的方式
Celery是定时任务处理和调度的分布式任务队列,常用于web异步任务、定时任务等。