Django 使用 Celery 实现异步任务
对于网站来说,给用户一个较好的体验是很重要的事情,其中最重要的指标就是网站的浏览速度。因此服务端要从各个方面对网站性能进行优化,比如可采用CDN加载一些公共静态文件,如js和css;合并css或者js从而减少静态文件的请求等等…..还有一种方法是将一些不需要立即返回给用户,可以异步执行的任务交给后台处理,以防网络阻塞,减小响应时间。看了the5fire的博客之后我受到了启发,决定从这方面进行改进。
我采用celery实现后台异步执行的需求。对于celery,先看一下网上给的celery的定义和用途:
1
2
3
4
5
|
Celery is a simple, flexible, and reliable distributed system to process vast amounts of messages, while providing operations with the tools required to maintain such a system.
It’s a task queue with focus on real-time processing, while also supporting task scheduling.
Celery has a large and diverse community of users and contributors, you should come join us on IRC or our mailing-list.
|
上面的英文还是比较好理解的,简而言之,就是一个专注于实时处理和任务调度的分布式队列。
我买了一本《Python Web开发实战》,那里面也介绍了celery。说了使用celery的常见场景:
- Web应用。当用户触发一个动作需要较长时间来执行完成时,可以把它作为任务交给celery异步执行,执行完再返回给用户。这点和你在前端使用ajax实现异步加载有异曲同工之妙。
- 定时任务。假设有多台服务器,多个任务,定时任务的管理是很困难的,你要在不同电脑上写不同的crontab,而且还不好管理。Celery可以帮助我们快速在不同的机器设定不同任务。
- 其他可以异步执行的任务。比如发送短信,邮件,推送消息,清理/设置缓存等。这点还是比较有用的。
综上所述,第1点和第3点的用途是我考虑celery的原因。目前,考虑在Django中实现两个功能:
- 文章阅读量的统计
- 发送邮件
关于文章阅读量的统计,我之前的做法就是在用户每一次访问文章的时候,都会同步执行一遍+1的函数,现在打算用异步执行的方式。
下面介绍在Django中的使用方法:
1、环境准备
安装celery,rabbitmq,django-celery.
2、启动消息中间件rabbitmq。
用它的原因是celery官方推荐的就是它,也可以用Redis等,但Redis会因为断电的原因造成数据全部丢失等问题。
让其在后台运行:
1
|
sudo rabbitmq-server -detached
|
3、在Django中配置(源代码)
项目代码结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
dailyblog
├── blog
│ ├── models.py
│ ├── serializer.py
│ ├── tasks.py
│ ├── urls.py
│ ├── views.py
├── config.yaml
├── dailyblog
│ ├── celery.py
│ ├── __init__.py
│ ├── __init__.pyc
│ ├── settings.py
│ ├── urls.py
│ ├── wsgi.py
|
对于celery的配置,需要编写几个文件:
1
2
3
4
5
6
7
|
1、dailyblog/celery.py
2、dailyblog/settings.py
3、blog/tasks.py
4、dailyblog/__init__.py
|
1、dailyblog/celery.py
本模块主要是创建了celery应用,配置来自django的settings文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from __future__ import absolute_import,unicode_literals #目的是拒绝隐士引入,celery.py和celery冲突。
import os
from celery import Celery
from django.conf import settings
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyblog.settings")
#创建celery应用
app = Celery('dailyblog')
#You can pass the object directly here, but using a string is better since then the worker doesn’t have to serialize the object.
app.config_from_object('django.conf:settings')
#如果在工程的应用中创建了tasks.py模块,那么Celery应用就会自动去检索创建的任务。比如你添加了一个任务,在django中会实时地检索出来。
app.autodiscover_tasks(lambda :settings.INSTALLED_APPS)
|
关于config_from_object,我对于如何加载配置文件还是比较感兴趣的,于是研究了一下源码,具体可以见:“celery加载配置文件”。
2、settings.py
配置celery,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import djcelery
djcelery.setup_loader()
#末尾添加
CELERYBEAT_SCHEDULER = ‘djcelery.schedulers.DatabaseScheduler‘ # 这是使用了django-celery默认的数据库调度模型,任务执行周期都被存在你指定的orm数据库中
#INstalled_apps
INSTALLED_APPS = (
‘django.contrib.admin‘,
‘django.contrib.auth‘,
‘django.contrib.contenttypes‘,
‘django.contrib.sessions‘,
‘django.contrib.messages‘,
‘django.contrib.staticfiles‘,
‘djcelery‘, #### 这里增加了djcelery 也就是为了在django admin里面可一直接配置和查看celery
‘blog‘, ###
)
|
setup_loader目的是设定celery的加载器,源码:
1
2
3
4
|
def setup_loader(): # noqa
os.environ.setdefault(
b'CELERY_LOADER', b'djcelery.loaders.DjangoLoader',
)
|
3、dailyblog/init.py
1
2
3
4
5
|
from __future__ import absolute_import
# 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
|
4、blog/tasks.py
1
2
3
4
5
6
7
8
9
|
from django.db.models import F
from .models import Article
from dailyblog import celery_app
@celery_app.task
def incr_readtimes(article_id):
return Article.objects.filter(id=article_id).update(read_times=F('read_times') + 1)
|
这里面添加了一个任务。任务可以通过delay方法执行,也可以周期性地执行。
这里还需要注意,如果把上面任务的返回值赋值给一个变量,那么程序也会被阻塞,需要等待异步任务返回的结果。因此,实际应用不需要赋值。
上面的代码写好后,要执行数据库更新:厦门租叉车
1
2
|
python manage.py makemigrations
python manage.py migrate.
|
Django会创建了几个数据库,分别为:
Crontabs Intervals Periodic tasks Tasks Workers
在views.py添加异步任务:
1
2
3
4
5
6
7
|
from .tasks import incr_readtimes
class ArticleDetailView(BaseMixin,DetailView):
def get(self, request, *args, **kwargs):
.......
incr_readtimes.delay(self.object.id)
|
这里不需要赋值。
下面要启动celery,我采用supervisor进程管理器来管理celery:
1
2
3
4
5
6
7
8
9
10
|
[program:celery]
command= celery -A dailyblog worker --loglevel=INFO
directory=/srv/dailyblog/www/
numprocess=1
startsecs=0
stopwaitsecs=0
autostart=true
autorestart=true
stdout_logfile=/tmp/celery.log
stderr_logfile=/tmp/celery.err
|
重新加载supervisor.conf文件,然后启动celery:
1
|
supervisorctl start celery
|
至此,通过celery异步执行任务的程序写完了。除此之外,还可以写很多的异步任务,发邮件就是非常典型的一种。
Django 使用 Celery 实现异步任务的更多相关文章
- Django使用Celery进行异步任务
Celery Celery是一个功能完备即插即用的异步任务队列系统.它适用于异步处理问题,当发送邮件.或者文件上传, 图像处理等等一些比较耗时的操作,我们可将其异步执行,这样用户不需要等待很久,提高用 ...
- Django配置celery执行异步任务和定时任务
原生celery,非djcelery模块,所有演示均基于Django2.0 celery是一个基于python开发的简单.灵活且可靠的分布式任务队列框架,支持使用任务队列的方式在分布式的机器/进程/线 ...
- Django搭配Celery进行异步/定时任务(一)初步搭建
以下需求场景很常见: 1. 用户点击页面按钮,请求后台进行一系列耗时非常高的操作,页面没有响应/一直Loading,用户体验非常不好. 2. 某些数据需要预先处理,每天凌晨的时候进行运算,大约半小时到 ...
- django 使用celery 实现异步任务
celery 情景:用户发起request,并等待response返回.在本些views中,可能需要执行一段耗时的程序,那么用户就会等待很长时间,造成不好的用户体验,比如发送邮件.手机验证码等. 使用 ...
- Django使用Celery异步任务队列
1 Celery简介 Celery是异步任务队列,可以独立于主进程运行,在主进程退出后,也不影响队列中的任务执行. 任务执行异常退出,重新启动后,会继续执行队列中的其他任务,同时可以缓存停止期间接收 ...
- Django项目中使用celery做异步任务
异步任务介绍 在写项目过程中经常会遇到一些耗时的任务, 比如:发送邮件.发送短信等等~.这些操作如果都同步执行耗时长对用户体验不友好,在这种情况下就可以把任务放在后台异步执行 celery就是用于处理 ...
- Django+Celery 执行异步任务和定时任务
celery是一个基于python开发的简单.灵活且可靠的分布式任务队列框架,支持使用任务队列的方式在分布式的机器/进程/线程上执行任务调度.采用典型的生产者-消费者模型,主要由三部分组成: 1. 消 ...
- Django中Celery http请求异步处理(四)
Django中Celery http请求异步处理 本章延续celery之前的系列 1.settings配置 2.编写task jib_update_task任务为更新salt jid数据 3.url设 ...
- django、celery异步发邮件
django.celery异步发邮件 django自带的send_mail发邮件功能执行发邮件功能会因为网络的原因造成花费的时间过长,为了解决这个问题,可以用celery + redis代替 安装包: ...
随机推荐
- 位图索引对于DML操作的影响
位图索引相对于常规的B-tree 索引,有着体积更加小的优势,节省空间.对于重复率特别高的字段,比如性别,比如省份.查询效率要优于B-tree 索引.那为什么我们总被告知在业务库中不要使用呢? 业务库 ...
- java8 新特性 Stream流 分组 排序 过滤 多条件去重
private static List<User> list = new ArrayList<User>(); public static void main(String[] ...
- python2与python3的input函数的区别
Python3.x 中 input() 函数接受一个标准输入数据,返回为 string 类型. Python2.x 中 input() 相等于 eval(raw_input(prompt)) ,用来获 ...
- shell习题第10题:打印每个单词的字数
[题目要求] 用shell打印下面这句话中字母数小于6的单词. Bash also interprets a number of multi-character options. [核心要点] for ...
- vue---class和style的基本用法
不多BB了 直接上代码了 通俗移动易懂总结了5种常用改变样式 的形式 <style> .actived2{ color:red; } </style> </head> ...
- Delphi Android USB Interface with the G2
来源:http://www.bverhue.nl/g2dev/?p=65 Delphi Android USB Interface with the G2 Leave a reply I first ...
- java爬虫爬取网页内容前,对网页内容的编码格式进行判断的方式
近日在做爬虫功能,爬取网页内容,然后对内容进行语义分析,最后对网页打标签,从而判断访问该网页的用户的属性. 在爬取内容时,遇到乱码问题.故需对网页内容编码格式做判断,方式大体分为三种:一.从heade ...
- Security 安全框架1
security 过滤器链 检查请求是否有请求信息-主要校验规则 UsernamePasswordAuthenticationFilter: 处理表单登录, 请求是否带用户名密码 BasicAuthe ...
- python3 str各个功能记录
capitalize() 将字符串的第一个字符转换为大写 center(width, fillchar) 返回一个指定的宽度 width 居中的字符串,fillchar 为填充的字符,默认为空格. c ...
- 用树莓派和DS18B20做个汽车温度记录仪[原创]
用树莓派和DS18B20做个汽车温度记录仪[原创] 很想知道夏日阳光暴晒下,汽车内的最高温度以及温度的变化情况.觉得用树莓派和DS18B20来实现应该很简单,于是就尝试捣鼓了一下,半天时间就搞定了,写 ...