Celery在Python中的基本使用
1. Celery简单介绍
1.1 简介Celery是什么?
Celery是一个基于Python开发的强大工具,旨在处理分布式异步任务队列。
1.2 具体的案例
在日常的后端对于IO阻塞较大的事件中,我们需要将事件异步执行,而不能进行同步执行。
例如:用户请求获取验证码时,我们需要向短信服务商调用请求接口去发送短信验证码,但是如果短信服务商网络出现波动,如果我们后端一直拼命的等待发送的结果,那对于用户来说,他并不知道短信到底有没有发送成功,就会疯狂的点击按钮尝试发送,所以我们应该先返回发送成功,然后将短信的发送事件添加到异步队列中,让他在慢慢执行,直到执行成功为止。
而正常来说,这件事儿我们也许会通过多线程/多进程进行提交,但是我们自己写的线程/进程逻辑,一方面来说性能优化问题,尤其是还有GIL锁对于线程限制,并且写起来也比较繁琐,所以这里我们引入了Celery,一个分布式任务队列,来处理我们的异步任务!
1.3 基本机制
Celery 通过消息机制进行通信,通常使用中间人(Broker)作为客户端和职程(Worker)调节。启动一个任务,客户端向消息队列发送一条消息,然后中间人(Broker)将消息传递给一个职程(Worker),最后由职程(Worker)进行执行中间人(Broker)分配的任务。
而我们要做的,就是定义好三个东西:
- 消息中间件(一般是RabbitMQ或者Redis)
- 任务(说白了,就是要干的事儿,比如是发短信还是发邮箱)
- 结果储存(Backend) (一般和消息中间件一样,但是不放在一个库中,例如一个在Redis的库1,一个在库2)
2. 创建消息中间件Broker及定义结果存储
2.1 定义Celery的各种参数
Celery默认使用RabbitMQ作为消息中间件,但是在这里使用我们最常用的缓存数据库Redis作为演示
创建tasks.py文件
import time
import celery
broker = 'redis://192.168.32.128:6379/8' # 定义消息中间件的存储库是 8
backend = 'redis://192.168.32.128:6379/9' # 定义结果存储库是 9
app = celery.Celery(
'Test',
broker=broker,
backend=backend
)
# 创建一个celery实例
@app.task #使用 实例.task装饰器,定义我们需要加入到消息队列的函数
def send_sms(phone,msg):
"""模拟用户发短信的需求"""
time.sleep(2)
print(f'给{phone}发送短信:{msg}')
return True
2.2 启动celery服务,让其不断监控消息中间件
tasks.py同目录的终端中执行以下代码
celery -A 定义实例的py文件名(不带.py) worker -l (日志的等级)
# eg:
celery -A tasks worker -l INFO
# ↑ 创建tasks.py中定义的实例配置对应的celery服务,日志等级INFO
2.3 Windows的踩坑!!
Celery 4.0 以上的版本中,必须指定以下参数
-P 其他并发池
# eg:
celery -A tasks worker -l INFO -P eventle
# 使用 Eventlet库的并发池,需要pip install eventlet
celery -A tasks worker -l INFO -P threads
# 使用线程作为并发
才能够正常运行,否则会一直阻塞不运行程序
为什么一定要指定这个参数?
官方文档中,其实已经表明了不再支持Windows
Does Celery support Windows?
Answer: No.
Since Celery 4.x, Windows is no longer supported due to lack of resources.
But it may still work and we are happy to accept patches.
翻译:从4.x开始,Windows由于缺乏资源,不再受支持,但是仍然可能可以使用,我们很乐意接收补丁。
所以,默认使用的Prefork Pool并发池,不再支持Windwos,但是指定其他并发池,仍然可以使用。
3. 提交事件到消息中间件(让函数执行)
提交事件,直接调用已经被装饰器装饰过的方法.delay(参数…)就可以将事务提交
例如创建main.py
from tasks import send_sms # 导入刚刚定义的函数
result = send_sms.delay('666666', '验证码666666')
# 调用被装饰器装饰后的函数.delay(参数)即可提交任务
print(result.id) # 提交完成后,通过.id可以获取到事务的id
result_2 = send_sms.delay('888888', '验证码888888')
print(result_2.id)
直接运行后,可以发现事件已经执行
4. 获取执行结果
获取执行结果,需要用到celery.result下的AsyncResult类,进行获取
from tasks import app # 导入celery的实例App
from celery.result import AsyncResult # 导入AsyncResult类
async_result = AsyncResult(id='e0ed9182-7391-4992-8660-6a0711aea159',app=app)
# 获取一个异步结果实例,需要id就是提交事件的时候返回的id,app就是对应的实例App
if async_result.successful():
"""successful返回是否执行成功"""
print(f'执行成功,结果:{async_result.result}')
elif async_result.failed():
"""successful返回是否执行失败"""
print(f'执行失败!!')
elif async_result.status == 'PENDING':
"""successful返回任务是否还在等待"""
print(f'任务等待被执行中...')
elif async_result.status == 'RETRY':
"""successful返回任务是否在重试阶段"""
print(f'任务重试中...')
返回任务是否还在等待"“”
print(f’任务等待被执行中…‘)
elif async_result.status == ‘RETRY’:
“”“successful返回任务是否在重试阶段”“”
print(f’任务重试中…’)