背景
在开发中,我们常常会遇到一些耗时任务,举个例子:
上传并解析一个 1w 条数据的 Excel 文件,最后持久化至数据库。
在我的程序中,这个任务耗时大约 6s,对于用户来说,6s 的等待已经是个灾难了。
比较好的处理方式是:
- 接收这个任务的请求
- 将这个任务添加到队列中
- 立即返回「操作成功,正在后台处理」的字样
- 后台消费这个队列,执行这个任务
我们按照这个思路,借助 Celery 进行实现。
实现
本文所使用的环境如下:
- Python 3.6.7
- RabbitMQ 3.8
- Celery 4.3
使用 Docker 安装 RabbitMQ
Celery 依赖一个消息后端,可选方案有 RabbitMQ, Redis 等,本文选用 RabbitMQ 。
同时为了安装方便,RabbitMQ 我直接使用 Docker 安装:
docker run -d --name anno-rabbit -p 5672:5672 rabbitmq:3
启动成功后,即可通过 amqp://localhost 访问该消息队列。
安装并配置 Celery
Celery 是 Python 实现的工具,安装可以直接通过 Pip 完成:
pip install celery
同时假设当前我的项目文件夹为 proj ,项目名为 myproj ,应用名为 myapp
安装完成后,在 proj/myproj/ 路径下创建一个 celery.py 文件,用来初始化 Celery 实例:
proj/myproj/celery.py
from __future__ import absolute_import, unicode_literals import os from celery import Celery, platforms # set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproj.settings') app = Celery('myproj', broker='amqp://localhost//', backend='amqp://localhost//') # Using a string here means the worker don't have to serialize # the configuration object to child processes.s # - namespace='CELERY' means all celery-related configuration keys # should have a `CELERY_` prefix. app.config_from_object('django.conf:settings', namespace='CELERY') # Load task modules from all registered Django app configs. app.autodiscover_tasks()
然后在 proj/myproj/__init__.py 中添加对 Celery 对象的引用,确保 Django 启动后能够初始化 Celery:
proj/myproj/__init__.py
from __future__ import absolute_import, unicode_literals # This will make sure the app is always imported when # Django starts so that shared_task will use this app. from .celery import app as celery_app __all__ = ('celery_app',)
无其他特殊配置的话,Celery 的基本配置就是这些。
编写一个耗时任务
为了模拟一个耗时任务,我们直接创建一个方法,使其「睡」10s ,并将其设置为 Celery 的任务:
proj/myapp/tasks.py
import time from myproj.celery import app as celery_app @celery_app.task def waste_time(): time.sleep(10) return "Run function 'waste_time' finished."
启动 Celery Worker
Celery 配置完成,并且任务创建成功后,我们以异步任务的模式启动 Celery :
celery -A myproj worker -l info
注意到我强调了异步模式,是因为 Celery 除了支持异步任务,还支持定时任务,因此启动时候要指明。
同时要注意,Celery 一旦启动,对 Task(此处为 waste_time) 的修改必须重启 Celery 才会生效。
任务调用
在请求处理的逻辑代码中,调用上面创建好的任务:
proj/myapp/views.py
from django.http import JsonResponse from django.views.decorators.http import require_http_methods from .tasks import waste_time @require_http_methods(["POST"]) def upload_files(request): waste_time.delay() # Status code 202: Accepted, 表示异步任务已接受,可能还在处理中 return JsonResponse({"results": "操作成功,正在上传,请稍候..."}, status=202)
调用 waste_time.delay() 方法后, waste_time 会被加入到任务队列中,等待空闲的 Celery Worker 调用。
效果
当我们发送请求时,这个接口会直接返回 {"results": "操作成功,正在上传,请稍候..."} 的响应内容而非卡住十秒,用户体验要好许多。
总结
用 Celery 处理这种异步任务是 Python 常用的方法,虽然实际执行成功耗时不变甚至有所增加(如 Worker 繁忙导致处理滞后),但是对于用户体验来说更容易接受,点击上传大文件后可以继续处理其他事务,而不需要在页面等待。
Celery 还有更多用法本文未介绍到,其文档已经非常详尽,有需要可直接参考。
参考
http://docs.celeryproject.org/en/latest/django/first-steps-with-django.html
https://hub.docker.com/_/rabbitmq
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- 雨林唱片《赏》新曲+精选集SACD版[ISO][2.3G]
- 罗大佑与OK男女合唱团.1995-再会吧!素兰【音乐工厂】【WAV+CUE】
- 草蜢.1993-宝贝对不起(国)【宝丽金】【WAV+CUE】
- 杨培安.2009-抒·情(EP)【擎天娱乐】【WAV+CUE】
- 周慧敏《EndlessDream》[WAV+CUE]
- 彭芳《纯色角3》2007[WAV+CUE]
- 江志丰2008-今生为你[豪记][WAV+CUE]
- 罗大佑1994《恋曲2000》音乐工厂[WAV+CUE][1G]
- 群星《一首歌一个故事》赵英俊某些作品重唱企划[FLAC分轨][1G]
- 群星《网易云英文歌曲播放量TOP100》[MP3][1G]
- 方大同.2024-梦想家TheDreamer【赋音乐】【FLAC分轨】
- 李慧珍.2007-爱死了【华谊兄弟】【WAV+CUE】
- 王大文.2019-国际太空站【环球】【FLAC分轨】
- 群星《2022超好听的十倍音质网络歌曲(163)》U盘音乐[WAV分轨][1.1G]
- 童丽《啼笑姻缘》头版限量编号24K金碟[低速原抓WAV+CUE][1.1G]