Celery介绍以及使用

celery

转载地址:https://www.cnblogs.com/pyedu/p/12461819.html
视频讲解:https://www.bilibili.com/video/BV1Pa4y1Y7QN?p=1

一、什么是celery

1、celery是什么:

  • celery是一个分布式队列的管理工具

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

  • 在这里插入图片描述

  • Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker),任务执行结果存储(task result store)

2、使用场景

  • celery是一个强大的分布式任务队列的异步处理框架,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。我们通常使用它来实现异步任务(async task)和定时任务(crontab)
  • 异步任务:将耗时操作任务提交给Celery去异步执行,比如发送短信/邮件、消息推送、音视频处理等等
  • 定时任务:定时执行某件事情,比如每天数据统计

3、Celery的优点

  • Simple简单:因为Celery作为一个对并发技术做了封装的框架,给别人使用和维护都不能做的很复杂,别人也不用太去了解底层的东西。
  • Highly Available高可用:在分布式系统下,一定要做到高可用,保证分布式服务器中的程序对外供给的时间有一个最大的利用率,还要做到稳定
  • Fast快速:单个Celery进程每分钟可以处理百万级的任务
  • Flexible灵活:Celery几乎每个部分都可以扩展使用,自定义池实现、序列化、压缩方案、日志记录、调度器、消费者、生产者、broker传输等等。由于语法上调用比较简单,比如要将消息中间件由RabbitMQ换成Redis,则只需要去配置文件修改一下对应的IP和端口即可,其他配置都不太需要更改

4、Celery的安装

  • pip install -U Celery
    
  • sudo easy_install Celery
    

二、Celery执行异步任务

在这里插入图片描述

在这里插入图片描述

1、创建异步任务执行文件(消费者)

  • celery_task.py

    • import celery
      import time
      # backend(后台),就是task result store
      backend = 'redis://127.0.0.1:6379/1'
      # broker 消息中间件
      broker = 'redis://127.0.0.1:6379/2'	
      # 实例化一个celery对象,test只是个名字,可以任意改
      cel = celery.Celery('test', backend=backend, broker=broker)
      
      @cel.task # 使用celery中的装饰器将函数装饰成celery任务(可能是异步任务,可能是定时任务)
      def send_mail(name):
          print('向%s 发送邮件...'%name)
          time.sleep(5)
          print('向%s 发送邮件完成'%name)
          return 'ok'
      
      @cel.task
      def send_msg(name):
          print('向%s 发送短信...' % name)
          time.sleep(5)
          print('向%s 发送短信完成' % name)
          return 'ok'
      
  • 在命令行中使用命令去启动异步任务执行文件,使worker去监听消息队列,若消息队列中有celery任务,则会去执行celery任务

    • celery worker -A clery_task -l info
      

2、创建生产者文件

生产者文件才是celery框架的主文件,当运行对应的文件时,生产者会将celery任务放入消息队列中。

  • produce_task.py

    • from celery_task import *
      result = send_mail.delay('hhh')#这里的result的值并不是send_mail函数的返回值ok,而是该函数的对象,返回值ok存储在backend中
      print(result.id)  
      result2 = send_msg.delay('ggg')
      print(result2.id)
      

3、创建result文件去获取任务函数的返回值,从而查看任务执行结果

  • result.py

    • from celery.result import AsyncResult
      from celery_task import cel
      
      #id为函数对象中的id,要查询哪一个函数的结果就输入哪一个函数的对象对应的id
      async_result = AsyncResult(id='531248c5-75ac-46af-8f01-889da554d7d6', 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('任务已经开始被执行')
      

4、多目录结构

  • 个人理解:多目录结构其实就是执行多个任务的意思,执行多个任务自然需要把对应的逻辑代码进行解耦,下面所说的单目录结构其实没有这种说法,只是个人为了与多目录结构多比较才这样说的,大概意思是把所有逻辑代码文件都放在一个目录下,这样耦合程度高,不好做代码的维护。

  • 多目录结构相对于单目录结构的优势在于解耦程度高,代码发生错误时好维护

  • 多目录结构中的代码和单目录结构是一样的,注意celery_tasks是一个包结构

  • 在这里插入图片描述
    在这里插入图片描述

  • celery.py:编写一些配置选项

    • import celery
      backend = 'redis://127.0.0.1:6379/1'
      broker = 'redis://127.0.0.1:6379/2'
      	
      cel = celery.Celery('test',
                          backend=backend,
                          broker=broker,
                          include=['celery_tasks.task01','celery_tasks.task02'])
      
      # 时区
      # cel.conf.timezone = 'Asia/Shanghai'
      # 是否使用UTC
      # cel.conf.enable_utc = False
      
  • task01.py:任务1

    • from celery_tasks.celery import cel
      import  time
      
      @cel.task
      def send_mail(name):
          print('发送邮件 %s' % name)
          time.sleep(5)
          return '邮件发送成功'
      
      
  • task02.py:任务2

    • from celery_tasks.celery import cel
      import time
      
      @cel.task
      def send_msg(name):
          print('发送短信 %s'%name)
          time.sleep(5)
          return '短信发送成功'
      
  • produce_task.py:主函数(生产者函数)

    • from celery_tasks.task01 import send_mail
      from celery_tasks.task02 import send_msg
      result = send_mail.delay('hhh')
      print(result.id)
      result2 = send_msg.delay('ggg')
      print(result2.id)
      
  • check_result.py:检查结果的函数

    • from celery.result import AsyncResult
      from celery_tasks.celery import cel
      
      async_result = AsyncResult(id='4e4ad94a-5dc2-4939-b461-830ed168a0a0', app=cel)
      
      if async_result.successful():
          result = async_result.get()
          print(result)
          # result.forget()  # 将结果删除
          # async_result.revoke(terminate=True)  # 无论现在是什么时候,都要终止
          # async_result.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('任务已经开始被执行')
      

5、异步任务和定时任务

  • 异步任务是在同一时刻以异步的方式去执行celery任务,而定时任务是指定好了具体时间或者指定延迟去执行celery任务

  • 异步任务使用delay,定时任务使用apply_async,两者函数区别在于,apply_async中有eta参数,可以将时间对象传入,从而达到定时执行任务

  • 单目录结构都是写在生产者函数中

    • # 异步任务
      from celery_tasks.task01 import send_mail
      from celery_tasks.task02 import send_msg
      result = send_mail.delay('hhh')
      print(result.id)
      result2 = send_msg.delay('ggg')
      print(result2.id)
      
      # 定时任务:相对于异步任务来说只是添加了一个定时的时间和用apply_async替换delay方法
      from datetime import datetime, timedelta
      from celery_tasks.task01 import send_mail
      from celery_tasks.task02 import send_msg
      
      # 方式一:指定具体的时间去定时执行celery任务
      # dt为指定的具体时间对象
      dt = datetime(year=2020, month=8, day=2, hour=15, minute=8,second=0)
      # 默认使用utc时间
      dt_utc = dt.utcfromtimestamp(dt.timestamp())
      result = send_mail.apply_async(args=['Bob'], eta=dt_utc)
      print(result.id)
      
      # 方式二:指定一个delay时间,使celery任务延迟多久才去执行
      current_time = datetime.now()
      ct_utc = current_time.utcfromtimestamp(current_time.timestamp())
      time_delay = timedelta(seconds=10)
      task_time = ct_utc + time_delay
      
      result2 = send_msg.apply_async(args=['Michael'], eta=task_time)
      print(result2.id)
      

6、多目录结构下celery执行

  • 单目录结构下的执行步骤应该是:

    • 1、创建对应的包,里面编写celery的配置文件,celery任务的文件,使用celery worker -A proj -l info -P eventlet命令去启动消费者文件,去监听消息队列。
    • 2、在另外一个目录下创建生产者文件(主函数),生产者文件作用是将celery任务放到消息队列里面,然后执行文件监听到消息队列有celery任务的话则就会去执行消息队列中的celery任务
  • 多目录结构下定时任务的执行方式不同,不是通过生产者去将celery任务插入到消息队列中,而是通过使用命令celery beat -A proj去将celery任务定时的插入到消息队列中,生产者不参与,定时任务或异步任务的调度代码都会在消费者的配置文件中去编写

  • 多目录结构中的celery.py文件:

  • import crontab
    import celery
    from datetime import  timedelta, datetime
    backend = 'redis://127.0.0.1:6379/1'
    broker = 'redis://127.0.0.1:6379/2'
    
    cel = celery.Celery('celery_test',
                        backend=backend,
                        broker=broker,
                        include=['celery_tasks.task01','celery_tasks.task02'])
    
    # 时区
    cel.conf.timezone = 'Asia/Shanghai'
    # 是否使用UTC
    cel.conf.enable_utc = False
    
    # 使用celery beat -A proj 命令执行定义好的定时任务
    cel.conf.beat_schedule = {
        # 名字随意命名
        'add-every-5-seconds':{
            # 执行task01下的send_email函数
            'task': 'celery_tasks.task01.send_mail',
            # 每隔6秒执行一次
            # 'schedule': 6.0,
            # 每隔6分钟
            # 'schedule': crontab(minute="*/6"),
            'schedule':timedelta(seconds=6),
            'args': ('Bob',)
        },
        'add-every-special-date':{
            'task':'celery_tasks.task02.send_msg',
            # 'schedule':crontab(minute=42,hours=8,day_of_month=11, month_of_year=11),
            'schedule':timedelta(seconds=7),
            'args':('Michael',)
        }
    
    }
    
  • 顺序(看个人):先开启监听,后将任务放入到消息队列,所以是先celery worker后celery beat

  • 注意点

    • 如果关闭了监听,beat命令还开着的话,还是会继续将celery任务不断的插入到broker中(这里使用redis),即使后面关闭了beat,其实redis中还是存放了celery任务。会导致下次worker开启监听的时候,会执行redis上一次beat遗留下来的celery任务,我们可以手动删除redis中的任务,可以通过pycharm去连接redis并删除对应的key

    • import redis
      
      r = redis.Redis(host='127.0.0.1', port=6379, db=2)
      
      # 删除beat历史遗留下来的celery任务
      r.delete('celery')
      
      # 查看还有没有历史遗留任务
      for i in r.lrange('celery',0,-1):
          print(i)
      
      

三、Django中使用celery

注意点

  • 1、celery不支持python3.7
  • 2、celery4.x已经不支持windows了,celery==3.1.25还是支持的
  • 3、常见错误:https://blog.csdn.net/cn_1937/article/details/91992075

概念介绍

  • Django需要引入celery包,django充当生产者,celery包充当消费者

  • django职责:

    • 只需要在views函数中去调用celery包封装好的函数
  • celery包职责:

    • 1、编写配置文件:指定消息队列和任务结果存储的数据库
    • 2、编写主函数:实例化celery对象并给对象添加一些属性,例如指定加载的配置、执行加载的celery任务有哪些、
    • 3、编写celery任务函数
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oDLoyLjJ-1596387123648)(C:\Users\dujun\AppData\Roaming\Typora\typora-user-images\image-20200803003440969.png)]

总体流程

  • 1、定义好celery包
  • 2、django中写好调用celery的代码
  • 3、消费者开启监听:使用命令行启动,建议切换目录到mycelery根目录下启动,celery -A mycelery.main worker --loglevel=info
  • 4、开启django项目
  • 5、去访问对应的url触发异步任务

文件对应的代码

  • 配置文件config.py:

    • broker_url = 'redis://127.0.0.1:6379/15'
      result_backend = 'redis://127.0.0.1:6379/14'
      
  • 主程序main.py

    • # 主程序
      import os
      from celery import Celery
      # 创建celery实例对象
      app = Celery("sms")
      
      # 把celery和django进行组合,识别和加载django的配置文件
      os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'celeryPros.settings.dev')
      
      # 通过app对象加载配置
      app.config_from_object("mycelery.config")
      
      # 加载任务
      # 参数必须必须是一个列表,里面的每一个任务都是任务的路径名称
      # app.autodiscover_tasks(["任务1","任务2"])
      app.autodiscover_tasks(["mycelery.sms",])
      
      # 启动Celery的命令
      # 强烈建议切换目录到mycelery根目录下启动
      # celery -A mycelery.main worker --loglevel=info
      
  • 任务文件tasks.py

    • #  celery的任务必须写在名为tasks.py的文件中,因为主程序中加载celery任务的函数会自动识别名为tasks.py的文件
      from mycelery.main import app
      import time
      import logging
      
      log = logging.getLogger('django')
      
      @app.task
      def send_sms(name):    # name表示设置任务的名称,如果不填写,则默认为函数名
          print('邮件内容:%s'%name)
          time.sleep(5)
          return 'send_sms:ok'
      
      @app.task
      def send_sms2(name):
          print('邮件2内容:%s'%name)
          time.sleep(5)
          return 'send_sms2:ok'
      
  • Django视图调用views.py

    • from django.shortcuts import render, HttpResponse
      from mycelery.sms.tasks import send_sms, send_sms2
      # Create your views here.
      from datetime import datetime, timedelta
      
      def test(request):
          # 异步方式
          result = send_sms.delay('hi Bob')
          result2 = send_sms2.delay('hi Mechael')
          print(result.id)
          print(result2.id)
          # 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_sms.apply_async(["hi boy", ], eta=task_time)
          # print(result.id)
          return HttpResponse('OK')
      
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Django Celery 是一个用于 Django 框架的分布式任务队列工具。它结合了 Django 的 Web 开发能力和 Celery 的异步任务处理能力。通过使用 Celery,你可以将耗时的任务(如发送电子邮件、处理图像、执行定时任务等)从主线程中分离出来,以提高应用的性能和响应速度。 你可以通过以下步骤来集成 Django 和 Celery: 1. 安装 Celery:在命令行中使用 pip 安装 Celery 库:`pip install celery` 2. 配置 Celery:在 Django 项目的 settings.py 文件中配置 Celery 相关的设置,主要包括消息代理器(message broker)的设置和任务结果存储的设置。 3. 创建任务:在 Django 项目中创建需要异步执行的任务。任务是一个 Python 函数,使用 `@task` 装饰器进行标记。 4. 启动 Celery Worker:在命令行中使用 `celery -A your_project_name worker --loglevel=info` 启动 Celery Worker,该命令会监听并执行任务队列中的任务。 5. 触发任务:在你的 Django 代码中调用任务函数,可以使用 `your_task.delay()` 来触发异步执行任务。 这样,当你触发任务时,它会被添加到 Celery 的任务队列中,并由 Celery Worker 异步执行。执行结果可以存储在指定的结果存储中,也可以通过回调函数获取。 注意:配置消息代理器和结果存储器时,你可以选择使用不同的后端,如 RabbitMQ、Redis、Amazon SQS 等。 以上是关于 Django Celery 的简要介绍和基本使用步骤,如果你有具体问题或需要更详细的指导,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值