Celery介绍与使用

一.Celery介绍

Celery是一个功能完备即插即用的任务队列。它使得我们不需要考虑复杂的问题,
使用非常简单。celery看起来似乎很庞大,
本章节我们先对其进行简单的了解,然后再去学习其他一些高级特性。
celery适用异步处理问题,当发送邮件、或者文件上传, 图像处理等等一些比较耗时的操作,
我们可将其异步执行,这样用户不需要等待很久,提高用户体验。 celery的特点是:
* 简单,易于使用和维护,有丰富的文档。
* 高效,单个celery进程每分钟可以处理数百万个任务。
* 灵活,celery中几乎每个部分都可以自定义扩展。
celery非常易于集成到一些web开发框架中

二.Celery库和schedule库和APScheduler库对比

(Github Star21.2K)

  • celery 是经过生产级考量,但遇到问题,排查时候,比较坑,它的优势重在异步队列,虽也可用在定时任务。通常如果项目中已有Celery在使用,而且不需要动态添加定时任务时可以考虑使用;
    文档(http://www.celeryproject.org/)

(Github Star5.1K)

  • apscheduler 专注于定时任务,功能丰定,文档写得还算全,但没有对各个场景的详细说明。一些具体用法,还得去源代码,怎么调用,比如redis作为store。在实际使用过程中拥有最大的灵活性,可以满足我们的大部分定时任务的相关需求;
    文档(https://apscheduler.readthedocs.io/en/latest/)

(Github Star10.8K)

  • schedule 类似于linux的cron,简单好用。schedule非常轻量级,使用简单,但是不支持任务的持久化,也无法动态添加删除任务,所以主要用于简单的小型应用。
    文档(https://github.com/dbader/schedule)

三.安装Celery

pip install celery==5.3.0

celery不支持在windows下运行任务,需要借助eventlet来完成

pip install eventlet==0.33.3

Celery的默认broker(消息中间件)是RabbitMQ, 仅需配置一行就可以

使用Redis做broker(消息中间件)也可以 本地安装redis数据库(推荐使用 RabbitMQ)

pip install redis==4.5.5

四.基本使用

4.1创建应用

新建tasks.py文件

from celery import Celery
import time
# 我们这里案例使用redis作为broker
app = Celery('demo',
             backend='redis://@127.0.0.1:6379/2',
             broker='redis://@127.0.0.1:6379/1')


# 创建任务函数
@app.task
def my_task(a,b):
    print("任务函数正在执行....100s")
    time.sleep(100)
    return a+b

@app.task
def my_task2(a,b):
    print("任务函数2正在执行....100s")
    time.sleep(100)
    return a+b
#启动Celery
celery -A tasks worker --loglevel=info -P eventlet  -c 10 
# -c是协程的数量,生产环境可以用1000

Celery介绍与使用_第1张图片

这时候出现一个报警,添加参数即可

app = Celery('demo',
             backend='redis://@127.0.0.1:6379/2',
             broker='redis://@127.0.0.1:6379/1',
             broker_connection_retry_on_startup=True)

官方文档这里会讲

https://docs.celeryq.dev/en/latest/_modules/celery/worker/consumer/consumer.html

Celery介绍与使用_第2张图片

启动成功

Celery介绍与使用_第3张图片

4.2调用任务

任务加入到broker队列中,以便刚才我们创建的celery workder服务器能够从队列中取出任务并执行。如何将任务函数加入到队列中,可使用delay()
创建main.py

from tasks import my_task,my_task2

ret=my_task.delay(1,2)
ret2=my_task2.delay(1,2)
#返回任务id
print(ret.id) #b6782be6-2e58-49b1-baca-2480439266d3
print(ret2.id) #9032fdad-a0af-40ce-8918-38bc28b4c882

在这里插入图片描述

4.3存储结果

如果我们想跟踪任务的状态,Celery需要将结果保存到某个地方。有几种保存的方案可选:SQLAlchemy、Django ORM、Memcached、 Redis、RPC (RabbitMQ/AMQP)。

创建result.py

from celery.result import AsyncResult
from tasks import app
import time

#任务id与4.2对应的
async_result=AsyncResult(id='b6782be6-2e58-49b1-baca-2480439266d3',app=app)
while True:
    if async_result.successful():
        result=async_result.get()
        print("result",result)
    elif async_result.failed():
        print("执行失败")
    elif async_result.status=='PENDING':
        print("任务等待中被执行")
    elif async_result.status == 'RETRY':
        print("任务异常后正在重试")
    elif async_result.status == 'STARTED':
        print("任务已经开始被执行")
    time.sleep(1)

更多关于result对象信息,请参阅下列网址:
http://docs.celeryproject.org/en/latest/reference/celery.result.html#module-celery.result

五.Celery的配置文件(优化版)

由于Celery的配置信息比较多,通常情况下,我们会创建一个Celery的配置文件, 这里命名为 celery_config.py
Celery介绍与使用_第4张图片
step1:新增文件celery添加如下代码:

from celery import Celery

# include:导入指定的任务模块
# 这一次创建 app,并没有直接指定 broker(消息中间件来接收和发送任务消息) 和 backend(存储结果)。而是在配置文件中。
app = Celery(
   'demo',
   include=[
      'celery_tasks.task1',
      'celery_tasks.task2',
   ]
)
# 通过Celery 实例加载配置模块
app.config_from_object(
   'celery_tasks.celery_config',
)

step2:在celery_tasks文件夹下新建一个celery_config.py文件(Celery的配置文件) 添加如下代码:

# 官方配置文档:查询每个配置项的含义。

# 

# broker(消息中间件来接收和发送任务消息)
broker_url = 'redis://localhost:6379/1'
# backend(存储worker执行的结果)
result_backend = 'redis://localhost:6379/2'

# 设置时间参照,不设置默认使用的UTC时间
timezone = 'Asia/Shanghai'
# 指定任务的序列化
task_serializer='json'
# 指定执行结果的序列化
result_serializer='json'

broker_connection_retry_on_startup=True

启动

celery -A celery_tasks worker --loglevel=info -P eventlet  -c 10

step3:在celery_tasks 文件夹下新建task1.py和task2.py文件

import time
from celery_tasks.celery import app

@app.task
def send_msg(name):
   print("完成向%s发生短信任务"%name)
   time.sleep(5)
   return "短信完成!"
import time
from celery_tasks.celery import app

@app.task
def send_email(name):
   print("完成向%s发生邮件任务"%name)
   time.sleep(5)
   return "邮件完成!"

step4:增加produce_task.py文件,代码如下,分别发送执行任务消息到broker

from celery_tasks.task1 import send_msg
from celery_tasks.task2 import send_email

result=send_msg.delay('yuan')
print(result.id)
result=send_email.delay('yuan')
print(result.id)#30ba1b0d-5d0f-46b0-89a9-f76474802377

step5:增加check_result.py文件,代码如下

from celery.result import AsyncResult
from celery_tasks.celery import app


async_result=AsyncResult(id='30ba1b0d-5d0f-46b0-89a9-f76474802377',app=app)


if async_result.successful():
    result=async_result.get()
    print("result",result)
elif async_result.failed():
    print("执行失败")
elif async_result.status=='PENDING':
    print("任务等待中被执行")
elif async_result.status == 'RETRY':
    print("任务异常后正在重试")
elif async_result.status == 'STARTED':
    print("任务已经开始被执行")

六.定时任务

未完待续…

你可能感兴趣的:(java,开发语言,python)