1.应用背景
在一个应用服务中,对时效性要求没那么高的业务场景,我们没必要等到所有任务执行完再返回结果。例用户注册场景中,保存了用户账号密码后即可返回,后续的账号激活邮件,可以一种异步形式去处理,这种异步操作可以用队列服务来实现,从而减少用户等待响应时间,获得更好的用户体验。
2.celery是什么?
Celery是Python语言实现的分布式队列服务,除了支持即时任务,还支持定时任务,Celery有5个核心角色:
(1)Task
任务(Task)就是你要去做的事,例如一个注册流程里有很多任务,给用户发验证邮件就是其中一个,这种耗时任务可以交给Celery去处理;还有一种任务是定时任务,比如每天定时统计网站的注册人数,这个也可以交给Celery去进行周期性处理。
(2)Broker
Broker的中文意思为经纪人,指市场上买卖双方提供中介服务的人。在Celery中介于生产者和消费者之间的经纪人,该角色类似于数据结构中的队列。例如一Web系统中,生产者是处理核心业务的Web程序,业务中会产生某些耗时任务,比如短信,生产者会把任务交给Broker,即将任务暂时放到队列中,等消费者来处理。消费者是Worker,是专门用于执行任务的后台服务。Worker将实时监控队列中是否有新的任务,若有就会进行处理。Celery本身不提供队列服务,一般用Redis或者RabbitMQ来扮演Broker的角色。
(3)Worker
Worker就是一直在后台执行任务的人,也称为任务的消费者,它会实时监控队列中有没有任务,若有就立即取出执行。
(4)Beat
Beat是一个定时任务调度器,它会根据配置定时将任务发送给Broker,等待Worker来消费。
(5)Backend
Backend用于保存任务的执行结果,每个任务都有返回值,比如发送邮件的服务会告诉我们有没有成功,这个结果就存在Backend中,当然并不总是需要关心任务的执行结果。
![](https://i-blog.csdnimg.cn/blog_migrate/4c628c32ff1ffb15fc19d142f585bbc4.png)
记住这五个角色,将有助于后面内容的理解。
入门:
本文假设安装redis作为broker,则需安装redis并启动redis服务。
1)安装celery和django-celery
pip install - U Celery
pip install django-celery
django-celery提供Celery集成;使用Django ORM和缓存后端存储结果,自动发现INSTALLED_APPS中列出的应用程序的任务模块等
同时为了项目可启动django-celery,需要将djcelery添加到django settings文件的INSTALLED_APPS中。
2)创建Celery实例
from celery import Celery
app = Celery('tasks', broker='redis://localhost:6379/0')
3)创建任务
from django.core.mail import send_mail
@app.task
def send_register_active_email(to_email, username, token):
'''发送激活邮件'''
# 组织邮件信息
subject = '天天生鲜欢迎信息'
message = ''
sender = settings.EMAIL_FROM
receiver = [to_email]
html_message = '<h1>%s, 欢迎您成为天天生鲜注册会员</h1>请点击下面链接激活您的账户<br/><a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s</a>' % (username, token, token)
send_mail(subject, message, sender, receiver, html_message=html_message)
time.sleep(5)
在没有Celery的情况下,程序顺序执行,每个步骤都需要等上一步执行完成。又叫同步操作,例如:
1.插入记录到数据库
2.发邮件
3.注册成功
就可以把发邮件任务放在一个任务中交给celery去异步执行,如此便不需要等待邮件发送完成就可以完成程序的执行。
1. 插入记录到数据库
2. 安排 celery 帮我去发邮件
3. 注册成功
第二步非常快,只需要将任务放入队列中,并不会等任务真正执行完,程序将直接执行后面部分。
4)启动Worker
启动Worker,监听Broker中是否有任务,命令:celery worker,你可能需要指定参数
celery -A tasks_name worker -l info
-A:指定celery实例在哪个模块中,例子中,celery实例在tasks.py文件中,启动成功后,能看到信息。
5)启动Worker
![](https://i-blog.csdnimg.cn/blog_migrate/a86051ee45d5221e2f4ff8fd6acfb16b.jpeg)
任务函数用app.task装饰器修饰之后,就会成为Celery中的一个Task。
6)启动Worker
在主程序中调用任务,将任务发送给Broker,而不是真正执行该任务,比如下图程序register
# user.py
from tasks import send_mail
def register():
import time
start = time.time()
print("1. 插入记录到数据库")
print("2. celery 帮我发邮件")
send_mail.delay("xx@gmail.com")
print("3. 告诉用户注册成功")
print("耗时:%s 秒 " % (time.time() - start))
if __name__ == '__main__':
register()
在主程序中调用函数.delay
方法,进行该函数的异步任务处理
若运行python user.py,启动应用程序
结果如下所示:
1. 插入记录到数据库
2. celery 帮我发邮件
3. 告诉用户注册成功
耗时:0.22688984870910645 秒
程序执行时间不到0.23秒。
在worker服务窗口看日志信息可发现邮件发送花了5秒。
![](https://i-blog.csdnimg.cn/blog_migrate/4e0ca7922ae847a647f61b5dfb62e8b0.png)