Celery 并发异步框架

1.什么是Celery

Celery是一个简单、灵活且可靠的,处理大量消息的分布式系统、专注于实时处理的异步任务队列、同时也支持任务调度。

2.消息中间件

Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ, Redis等等

3.任务执行单元

Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中。

4.任务结果存储

Task result store用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, redis等

5.Celery使用场景

异步任务:将耗时操作任务提交给Celery去异步执行,比如发送短信/邮件、消息推送、音视频处理等等

6.Celery的安装配置

pip install celery

消息中间件:RabbitMQ/Redis

app=Celery('任务名',backend='xxx',broker='xxx')

7.Celery执行异步任务

基本使用

celery_app_task.py

import celery

# 消息接收库
broker = 'redis://172.17.0.66:6379/2'

# 消息存储库
backend = 'redis://172.17.0.66:6379/1'

cel = celery.Celery('test', broker=broker, backend=backend)


@cel.task
def add(x, y):
    return x + y

@cel.task
def send_email(name):
    print("向%s发送邮件..." % name)
    time.sleep(1)
    print("向%s发送邮件完成" % name)
    return "ok"


@cel.task
def send_msg(name):
    print("向%s发送短信..." % name)
    time.sleep(1)
    print("向%s发送短信完成" % name)
    return "ok"

add_task.py,添加任务

from celery_app_task import send_email, send_msg,add

result = add.delay(4,4)
print(result.id)

result = send_email.delay("他")
print(result.id)

result = send_msg.delay("我")
print(result.id)

启动worker

celery -A celery_app_task worker -l info -P eventlet

result.py,查看任务执行结果

from celery.result import AsyncResult
from celery_app_task import cel

async_result = AsyncResult(id="d6dbc2d4-956a-46ed-93dc-71ca8a18a67e", app=cel)

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

8.Celery多目录异步执行

多任务结构

celery_tasklist
    ├── celery_task     # celery相关文件夹
    │   ├── celery.py   # celery连接和配置相关文件,必须叫这个名字
    │   └── task01.py    #  所有任务函数
    │	└── task02.py    #  所有任务函数
    ├── check_result.py # 检查结果
    └── send_task.py    # 触发任务

celery.py

from celery import Celery

cel = Celery('celery_demo',
             broker='redis://172.17.0.66:6379/1',
             backend='redis://172.17.0.66:6379/2',
             # 包含以下两个任务文件,去相应的py文件中找任务,对多个任务做分类
             include=['celery_task.task01',
                      'celery_task.task02'
                      ])

# 时区
cel.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
cel.conf.enable_utc = False

task01.py

import time
from celery_task.celery import cel


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

task02.py

import time
from celery_task.celery import cel


@cel.task
def send_msg(name):
    print("向%s发送短信..." % name)
    time.sleep(5)
    return "短信完成!!!"

send_task.py

from celery_task.task01 import send_email
from celery_task.task02 import send_msg

# 立即告知celery去执行send_email任务,并传入一个参数
result = send_email.delay('第一个的执行')
print(result.id)

result = send_msg.delay('第二个的执行')
print(result.id)

check_result.py

from celery.result import AsyncResult
from celery_task.celery import cel

async_result = AsyncResult(id="ad409177-a164-4dd7-9eca-0be5018b9fce", app=cel)

if async_result.successful():
    result = async_result.get()
    print(result)
    # result.forget() # 将结果删除,执行完成,结果不会自动删除
    # async.revoke(terminate=True)  # 无论现在是什么时候,都要终止
    # async.revoke(terminate=False) # 如果任务还没有开始执行呢,那么就可以终止。
elif async_result.failed():
    print('执行失败')
elif async_result.status == 'PENDING':
    print('任务等待中被执行')
elif async_result.status == 'RETRY':
    print('任务异常后正在重试')
elif async_result.status == 'STARTED':
    print('任务已经开始被执行')

添加任务(执行send_task.py),开启work:celery -A celery_task worker -l info -P eventlet ,检查任务执行结果(执行check_result.py)

9.Celery执行定时任务

基本使用

celery_tasks.py

import celery
import time

broker = 'redis://172.17.0.66:6379/2'

backend = 'redis://172.17.0.66:6379/1'

cel = celery.Celery('test', broker=broker, backend=backend)


@cel.task
def send_email(name):
    print("向%s发送邮件..." % name)
    time.sleep(1)
    print("向%s发送邮件完成" % name)
    return "ok"


@cel.task
def send_msg(name):
    print("向%s发送短信..." % name)
    time.sleep(1)
    print("向%s发送短信完成" % name)
    return "ok"

produce_task.py

from celery_tasks import send_email
from datetime import datetime, timedelta

# 方式一(定义哪个时间执行)
v1 = datetime(2022, 2, 18, 17, 26, 56)
print(v1)
v2 = datetime.utcfromtimestamp(v1.timestamp())
print(v2)
# args参数是传参
result = send_email.apply_async(args=["mzk"], eta=v2)
print(result.id)

# 方式二(延时多久执行)
ctime = datetime.now()
# 默认用utc时间
utc_ctime = datetime.utcfromtimestamp(ctime.timestamp())
time_delay = timedelta(seconds=10) # seconds设置多少秒
task_time = utc_ctime + time_delay
# 使用apply_async并设定时间
result = send_email.apply_async(args=["mzk"], eta=task_time)
print(result.id)

check_result.py

from celery.result import AsyncResult
from celery_tasks import cel

async_result = AsyncResult(id="2b35127e-bd74-42f9-9424-2842262f1549", app=cel)

if async_result.successful():
    result = async_result.get()
    print(result)
    # result.forget() # 将结果删除,执行完成,结果不会自动删除
    # async.revoke(terminate=True)  # 无论现在是什么时候,都要终止
    # async.revoke(terminate=False) # 如果任务还没有开始执行呢,那么就可以终止。
elif async_result.failed():
    print('执行失败')
elif async_result.status == 'PENDING':
    print('任务等待中被执行')
elif async_result.status == 'RETRY':
    print('任务异常后正在重试')
elif async_result.status == 'STARTED':
    print('任务已经开始被执行')

添加任务(执行celery_tasks.py),开启work:celery -A celery_task worker -l info -P eventlet ,检查任务执行结果(执行check_result.py)

10.Celery多目录下定时任务

多任务结构中celery.py修改如下

from celery import Celery
from celery.schedules import crontab
from datetime import timedelta

cel = Celery('celery_demo',
             broker='redis://172.17.0.66:6379/1',
             backend='redis://172.17.0.66:6379/2',
             # 包含以下两个任务文件,去相应的py文件中找任务,对多个任务做分类
             include=['celery_task.task01',
                      'celery_task.task02'
                      ])

# 时区
cel.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
cel.conf.enable_utc = False

cel.conf.beat_schedule = {
    # 名字随意命名
    'add-every-10-seconds': {
        # 执行task01下的send_email函数
        'task': 'celery_task.task01.send_email',
        # 每隔5秒执行一次
        # 'schedule': 1.0,
        # 'schedule': crontab(minute="*/1"),
        'schedule': timedelta(seconds=5),
        # 传递参数
        'args': ('mzk',)
    },
    # 'add-every-12-seconds': {
    #     'task': 'celery_task.tasks1.test_celery',
    #     每年4月11号,8点42分执行
    #     'schedule': crontab(minute=42, hour=8, day_of_month=11, month_of_year=4),
    #     'schedule': crontab(minute=42, hour=8, day_of_month=11, month_of_year=4),
    #     'args': (16, 16)
    # },
}

启动work执行:celery -A celery_task worker -l info -P eventlet # windows下使用eventlet多线程
启动一个beat:celery -A celery_task beat -l info # Celery Beat进程会读取配置文件的内容,周期性的将配置中到期需要执行的任务发送给任务队列

11.django中使用Celery

项目根目录创建celery包,目录结构如下

celery_tasklist
    ├── email    
    │   ├── __init__.py  
    │   └── tasks.py    #  任务函数
    ├── message    
    │   ├── __init__.py  
    │   └── tasks.py    #  任务函数
    ├── init__.py	 
    ├── config.py # redis或rabbitmq连接url和存储url
    └── main.py    # 加载django配置任务

email文件下tasks任务

# celery的任务必须写在tasks.py的文件中,别的文件名称不识别!!!
import logging

log = logging.getLogger("django")


@app.task  # name表示设置任务的名称,如果不填写,则默认使用函数名做为任务名
def send_email(name):
    print("向邮箱%s发送邮件成功!" % name)
    time.sleep(5)

    return "send_email OK"

message文件下tasks任务

# celery的任务必须写在tasks.py的文件中,别的文件名称不识别!!!
from djcelery.main import app
import time

import logging

log = logging.getLogger("django")


@app.task  # name表示设置任务的名称,如果不填写,则默认使用函数名做为任务名
def send_message(mobile):
    """发送短信"""
    print("向手机号%s发送短信成功!" % mobile)
    time.sleep(5)

    return "send_message OK"

config.py

broker_url = 'redis://172.17.0.66:6379/15'       # redis 中间件
result_backend = 'redis://172.17.0.66:6379/14'   # redis 存储库

main.py 主程序中对django的配置文件进行加载

import os
from celery import Celery
import djangoProject2

# 创建celery实例对象
app = Celery("djcelery")

# 把celery和django进行组合,识别和加载django的配置文件 djangoProject2是settings上的文件夹名称
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject2.settings') 

# 通过app对象加载配置
app.config_from_object("djcelery.config")

# 加载任务
# 参数必须必须是一个列表,里面的每一个任务都是任务的路径名称
# app.autodiscover_tasks(["任务1","任务2"])
app.autodiscover_tasks(["djcelery.email", "djcelery.message"])

启动Celery的命令
强烈建议切换目录到mycelery根目录下启动
celery -A djcelery.main worker -l info -P eventlet

views.py视图调用

from django.shortcuts import HttpResponse
from djcelery.email.tasks import send_email
from djcelery.message.tasks import send_message
from datetime import timedelta
from datetime import datetime


def user(request):

    # 异步任务
    # 1. 声明一个和celery一模一样的任务函数,但是我们可以导包来解决
    # send_email.delay("110")
    # send_message.delay("119")
    # send_sms.delay() 如果调用的任务函数没有参数,则不需要填写任何内容

    
    # 定时任务
    ctime = datetime.now()
    # 默认用utc时间
    utc_ctime = datetime.utcfromtimestamp(ctime.timestamp())
    time_delay = timedelta(seconds=10)
    task_time = utc_ctime + time_delay
    result = send_message.apply_async(["911", ], eta=task_time)
    # print(result.id)
    return HttpResponse('OK')
posted @   沈忻凯  阅读(124)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示