一、Celery介绍和基本使用
Celery官方文档:
Celery是什么?
Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery, 举几个实例场景中可用的例子:
Celery 在执行任务时需要通过一个消息中间件(Broker)来接收和发送任务消息,以及存储任务结果, 一般使用rabbitMQ or Redis
Celery有以下优点:
Celery执行流程图如下
二、Celery安装使用
安装celery模块
pip install celery==4.3.0
Celery的默认broker(消息中间件)是RabbitMQ, 仅需配置一行就可以
BROKER_URL = 'amqp://guest:guest@localhost:5672/yard'
使用Redis做broker(消息中间件)也可以 本地安装redis数据库(redis安装流程不再重复)
pip install redis
注意:
celery不支持在windows下运行任务,需要借助eventlet来完成
pip install eventlet
三、Celery异步任务使用代码示例
对比说明
不使用Celery的情况下我们执行一个耗时的任务,创建一个app.py 文件
import time
def add(x,y):
time.sleep(5)
return x+y
if **name** == '**main**':
print('task start....')
result = add.delay(2,3)
print('task end....')
print(result)
运行代码发现出现5秒后打印了结果
task start....
task end....
5
使用Celery执行(异步任务调度的情况)
step1:新建一个tasks.py文件
import time
from celery import Celery
#消息中间件(使用的redis)
broker = 'redis://localhost:6379/1'
#结果存储(使用的redis)
backend = 'redis://localhost:6379/2'
#实例化Celery对象
app = Celery(
'celeryDemo',
broker=broker,
backend=backend
)
# 添加@app.task()装饰器,说明执行的任务是一个异步任务
@app.task()
def add(x,y):
print('task enter ....')
time.sleep(5)
return x+y
step2:修改app.py文件,代码如下
from tasks import add
if **name** == '**main**':
print('task start....')
result = add.delay(2,3)
print('task end....')
print(result)
上述代码修改完毕后: 打开终端,进入项目下,运行 app.py文件
python3 app.py
注意:立即执行结果如下,此时我们可以看到反回了一个任务id(47ad971c-9a9a-44ca-bee4-a71f44eff048),并没有打印结果,因为没有执行worker端
运行worker端 打开终端,进入项目下,输入如下命令:
celery -A tasks worker -l info
# windows下启动的时候,使用eventlet 方式
# celery -A tasks worker --loglevel=info -P eventlet -c 10
# -c是协程的数量,生产环境可以用1000
结果如下:
-------------- celery@DESKTOP-9G0AUUR v5.2.3 (dawn-chorus)
--- ***** -----
-- ******* ---- Windows-10-10.0.19041-SP0 2022-03-23 12:22:13
+ *** --- * ---
+ ** ---------- [config]
+ ** ---------- .> app: celeryDemo:0x21eea2c6088
+ ** ---------- .> transport: redis://127.0.0.1:6379/1
+ ** ---------- .> results: redis://127.0.0.1:6379/2
+ ***--- * --- .> concurrency: 10 (eventlet)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
---***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. tasks.add
[2022-03-23 12:22:13,568: INFO/MainProcess] Connected to redis://127.0.0.1:6379/1
[2022-03-23 12:22:13,572: INFO/MainProcess] mingle: searching for neighbors
[2022-03-23 12:22:14,628: INFO/MainProcess] mingle: all alone
[2022-03-23 12:22:14,648: INFO/MainProcess] pidbox: Connected to redis://127.0.0.1:6379/1.
[2022-03-23 12:22:14,652: INFO/MainProcess] celery@DESKTOP-9G0AUUR ready.
[2022-03-23 12:22:14,657: INFO/MainProcess] Task tasks.add[47ad971c-9a9a-44ca-bee4-a71f44eff048] received
[2022-03-23 12:22:14,658: WARNING/MainProcess] task enter ....
[2022-03-23 12:22:14,662: INFO/MainProcess] Task tasks.add[47ad971c-9a9a-44ca-bee4-a71f44eff048] succeeded in 0.0s: 5
此时如果不断的向broker中发送消息,那么worker中就会接收到消息并执行 打开终端操作如下:
(blog) G:\Python\Django\celery使用>python
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from tasks import add # 导入执行的方法
>>> add.delay(2,5) # 发送异步任务消息
<AsyncResult: 8a660f76-a823-43ef-b5c4-e6760a839dca>
>>> result = add.delay(3,5)
>>> result.ready() # 查看异步任务是否执行完毕
True
>>> result.get() # 获取任务执行完毕后的结果
8
Celery的配置文件(优化版)
由于Celery的配置信息比较多,通常情况下,我们会创建一个Celery的配置文件, 这里命名为 celeryconfig.py
step1:
在之前的项目中创建一个celery_demo的python Package文件夹 在__init__.py中添加如下代码:
from celery import Celery
# include:导入指定的任务模块
# 这一次创建 app,并没有直接指定 broker(消息中间件来接收和发送任务消息) 和 backend(存储结果)。而是在配置文件中。
app = Celery(
'demo',
include=[
'celery_demo.task1',
'celery_demo.task2',
]
)
# 通过Celery 实例加载配置模块
app.config_from_object(
'celery_demo.celeryconfig',
)
step2:
在celery_demo文件夹下新建一个celeryconfig.py文件(Celery的配置文件) 添加如下代码:
# 官方配置文档:查询每个配置项的含义。
#
# broker(消息中间件来接收和发送任务消息)
BROKER_URL = 'redis://localhost:6379/1'
# backend(存储worker执行的结果)
CELERY_RESULT_BACKEND = 'redis://localhost:6379/2'
# 设置时间参照,不设置默认使用的UTC时间
CELERY_TIMEZONE = 'Asia/Shanghai'
# 指定任务的序列化
CELERY_TASK_SERIALIZER='json'
# 指定执行结果的序列化
CELERY_RESULT_SERIALIZER='json'
step3:在celery_demo文件夹下新建task1.py和task2.py文件
task1.py文件中执行如下代码
import time
from celery_demo import app
@app.task
def add(x,y):
time.sleep(5)
return x+y
task2.py文件中执行如下代码
import time
from celery_demo import app
@app.task
def mut(x,y):
time.sleep(5)
return x*y
step4:修改app.py文件,代码如下,分别发送执行任务消息到broker
from celery_demo import task1,task2
# apply_async和delay都表示调用异步任务
task1.add.delay(2,4)
# task1.add.apply_async(2,4)
task2.mut.delay(3,4)
print('end...')
查看运行结果,打开终端启动worker,如下则表示启动成功:
(blog) G:\Python\Django\celery使用>celery worker -A celery_demo -l INFO -P eventlet -c 10
-------------- celery@DESKTOP-9G0AUUR v4.3.0 (rhubarb)
---- **** -----
--- * **** -- Windows-10-10.0.19041-SP0 2022-03-23 16:26:31
-- * - **** ---
+ ** ---------- [config]
+ ** ---------- .> app: demo:0x2bc35c9ba08
+ ** ---------- .> transport: redis://localhost:6379/1
+ ** ---------- .> results: redis://localhost:6379/2
+ ***--- * --- .> concurrency: 10 (eventlet)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
---***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. celery_demo.task1.add
. celery_demo.task2.mut
[2022-03-23 16:26:39,476: INFO/MainProcess] Connected to redis://localhost:6379/1
[2022-03-23 16:26:41,532: INFO/MainProcess] mingle: searching for neighbors
[2022-03-23 16:26:48,671: INFO/MainProcess] mingle: all alone
[2022-03-23 16:26:50,701: INFO/MainProcess] pidbox: Connected to redis://localhost:6379/1.
[2022-03-23 16:26:54,765: INFO/MainProcess] celery@DESKTOP-9G0AUUR ready.
发送执行任务消息,打开终端,进行如下操作
(blog) G:\Python\Django\celery使用>python app.py
end...
此时会看到worker端接受到了两个任务并开始执行,如下所示:
[2022-03-23 16:28:30,167: INFO/MainProcess] Received task: celery_demo.task1.add[308aa4ce-2443-4618-b2e5-6a6a8c3dac4b]
[2022-03-23 16:28:30,169: INFO/MainProcess] Received task: celery_demo.task2.mut[dc0eed0a-75bf-4c69-a691-9cc39513db18]
[2022-03-23 16:28:35,190: INFO/MainProcess] Task celery_demo.task1.add[308aa4ce-2443-4618-b2e5-6a6a8c3dac4b] succeeded in 5.01600000000326s: 6
[2022-03-23 16:28:37,234: INFO/MainProcess] Task celery_demo.task2.mut[dc0eed0a-75bf-4c69-a691-9cc39513db18] succeeded in 7.061999999976251s: 12
四、定时任务
step1:
在之前代码的celery_demo文件夹下的celeryconfig.py文件中,添加如下代码
from datetime import timedelta
from celery.schedules import crontab
# 设置定时任务
CELERYBEAT_SCHEDULE = {
'task1':{
'task':'celery_demo.task1.add',
'schedule':timedelta(seconds=10), 表示每10秒发送一次任务消息
'args':(10,20)
},
'task2':{
'task':'celery_demo.task2.mut',
'schedule':crontab(hour=22,minute=24), #表示在每天的晚上10点24分发送一次任务消息
'args':(10,10)
}
}
step2:
启动定时消息任务,打开终端,执行如下命令
celery beat -A celery_demo -l INFO
启动
celery beat v4.3.0 (rhubarb) is starting.
__- ...__ - _
LocalTime -> 2022-03-23 16:19:33
Configuration ->
. broker -> redis://localhost:6379/1
. loader -> celery.loaders.app.AppLoader
. scheduler -> celery.beat.PersistentScheduler
. db -> celerybeat-schedule
. logfile -> [stderr]@%INFO
. maxinterval -> 5.00 minutes (300s)
[2022-03-23 16:19:33,228: INFO/MainProcess] beat: Starting...
如果要执行的是爬虫任务,只需要将上面的方法中的代码替换为爬虫代码即可。