在做网站后端开发时,会经常碰到这样类似的需求:用户需要在我们的网站填写注册信息,我们发给用户一封注册激活邮件到用户邮箱,由于某种原因,导致客户端需要等待比较久的时间才会有响应,这种体验非常不好:
- 之前想的是用多线程来解决,但是有可能会出现会几个问题:
1.并发比较大的时候,线程切换会有开销时间;
2.假如使用线程池会限制并发的数量;
3.多线程间的数据共享维护比较麻烦;
如果有东西能实现一下两点呢:
- 将耗时任务放到后台异步执行,不会影响用户其他操作。
- 还可以实现定时处理某些任务。
就像中介一样,本来你需要亲自去办理业务,然后在那里先排队,轮到你了才能办理业务,如果人很多,你就要等很久,干不了其他事。这时候如果你找中介,你就只用把事情交代清楚给中介,你就能去干下一件事情了,中介帮你干活,干好了就告诉你。
后来就自己找资料,发现有个celery蛮符合需求。
Celery(功能完备即插即用的任务队列)是一个用于执行异步任务的框架,它能很容易就能将Web应用中的一些耗时的作业转交给工作池,让工作池中的worker以异步的方式执行这些作业。且不会影响用户其他操作。
它可以让任务的执行同主程序完全脱离,甚至不在同一台主机内。它通过队列来调度任务,不用担心并发量高时系统负载过大。它可以用来处理复杂系统性能问题,却又相当灵活易用。
任务队列中包含称作任务的工作单元。有专门的工作进程持续不断的监视任务队列,并从中获得新的任务并处理。
celery通过消息进行通信,通常使用一个叫Broker(中间人)来协client(任务的发出者)和worker(任务的处理者)。 clients发出消息到队列中,broker将队列中的信息派发给worker来处理。
一个celery系统可以包含很多的worker和broker,可增强横向扩展性和高可用性能。
从图上可以看出Celery包含几个模块:
- 任务模块
主要包异步任务和定时任务,异步任务通常在业务逻辑中被触发并发送到任务队列中,而定时任务是由Celery Beat进程周期性的将任务发往任务队列。 - 消息中间件Broker
Broker就是任务调度队列,接受任务生产者发送来的消息,将任务存入队列,之所以需要中间人的原因是Celrey本身是不提供消息队列的服务,所以需要第三方组件实现(redis)。 - 任务执行单元Worker
Worker是执行任务的单元,它实时监控消息队列,如果有任务就获取任务并执行它。 - 任务存储Backend
Backend用于存储任务只想的结果,存储可以使用RabbitMQ或者Redis或者数据库等。
官方支持的Broker列表如下
PS:我自己测试Celery的时候,Broker和Backend配置的都是redis。
这里提一下,Celery支持多线程,且有几种模式,只不过需要自己去设置,默认是自己CPU的线程数。
- 建议单独设置一个需要用Celery文件夹,放在工程目录下,tasks文件夹就是我单独设置的。关于Celery主要的文件有两个,main.py和config.py。main.py做启动文件,config.py是配置文件,protask目录下的tasks.py是你需要放入队列中去运行的耗时任务,可以根据需要创建不同的tasks.py文件。
下面做一个简单的Celery例子:
- config.py
# coding=utf-8
#Broker和Backend,按自己实际选着的去配置,这里只是演示。
#Celery有很多配置选项能够使得celery能够符合我们的需要,但是默认的几项配置已经足够应付大多数应用场景了。
BROKER_URL = "redis://127.0.0.1:6379/1"
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/2'
- main.py
# coding=utf-8
#这里只做演示
from celery import Celery
from YouProjectName.tasks import config
# 定义celery对象
celery_app = Celery("projectname")
# 引入配置信息
celery_app.config_from_object(config)
# 自动搜寻异步任务
celery_app.autodiscover_tasks(["YouProjectName.tasks.protask"])
- tasks.py
# coding=utf-8
#把耗时间的任务从业务逻辑中剥离出来,写到tasks.py中,在业务逻辑中 import 你的tasks
#调用一下tasks中你写的就行了,如my_task1()
from YouProjectName.tasks.main import celery_app
# 创建任务函数
@celery_app.task
def my_task1():
print("任务函数(my_task1)正在执行....")
@celery_app.task
def my_task2():
print("任务函数(my_task2)正在执行....")
@celery_app.task
def my_task3():
print("任务函数(my_task3)正在执行....")
#proj换成你的main路径
celery -A proj worker -l info
Celery需要单独启动,启动方式和附带参数可以参考官方文档:
- http://docs.celeryproject.org/en/latest/userguide/workers.html
- http://docs.celeryproject.org/en/latest/reference/celery.bin.worker.html#cmdoption-celery-worker-n
启动成功后的界面
参考文档:
- http://docs.celeryproject.org/en/latest/index.html
- https://blog.csdn.net/cuomer/article/details/81214438
如有侵权,请联系我!!!