Celery消息推送

版权声明:大部分发布内容均为本人测试过程中保留笔记,如需转载请备注 https://blog.csdn.net/Jolting/article/details/85758370

学习内容:

  • celery介绍,以及原理
  • celery安装与配置
  • celery使用,路由配置
  • celery中其他模块(kombu-Queue,celery.utils.log)

学习目标

  •     了解celery的基本原理
  •     可配置celery,写简单的服务
  •     可编写一个定时任务--待续

一、celery基本介绍以及原理

(1)celery使用原因:

在程序运行过程中,我们经常会遇到一些耗时耗资源的操作,为了避免阻塞主程序,我们会采用异步或者多线程来处理任务。比如在主程序中调用一个函数,并从该函数中获取函数返回值。如果这个函数不能很快执行完成并返回,那么主程序就会阻塞,知直到函数返回。

(2)celery基本概念:

Celery是一个强大的分布式任务队列,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他的主机上运行。它是一个专注于实时处理的任务队列,同时也支持任务调度。

(3)celery实现原理:

原理图如下:

其中包含的模块有:

任务模块 :Task,包含异步任务和定时任务。其中,异步任务通常在业务逻辑中被触发并发往任务队列,而定时任务由 Celery Beat 进程周期性地将任务发往任务队列

消息中间件:Broker,即为任务调度队列,接收任务生产者发来的消息(即任务),将任务存入队列。Celery 本身不提供队列服务,官方推荐使用 RabbitMQ 和 Redis 等。

任务执行单元 :Worker, 是执行任务的处理单元,它实时监控消息队列,获取队列中调度的任务,并执行它

任务结果存储 :Backend,用于存储任务的执行结果,以供查询。同消息中间件一样,存储也可使用 RabbitMQ, Redis 和 MongoDB 等。

二、celery下载安装

(1)pip下载安装celery

$ pip install celery==3.1.0

tip:windows上不支持celery4.2版本,必须下载3.x版本

(2)pip下载celery所需队列(选择:redis)

$ pip install celery[redis]

(3)代码中使用

#需要导入包

from celery import Celery

三、celery使用

(1)celery实例的声明以及任务注册

①首先第一步,要导入celery模块

from celery import Celery

②第二步,实例化一个celery

app = Celery()

③第三步,将你的函数注册为celery需要监听的任务

@app.task

def add(a,b):

    return a+b

详情可看下面的代码

(2)调用任务,即将任务放入队列执行(以下两种中,看后端代码常用后一种)

①add.delay(a=34,b=45)

②app.send_task(task_routes,task_queue,task_params_list)

(3)celery读取配置

(4)celery配置文件中celery_queue,celery_routes的设置

以上的使用可以详情见后附代码

(如果没有celery模块,代码通过lpush值到redis,然后有一个while无线循坏的代码,通过blpop命令监控这个队列,blpop是redis的一个阻塞式命令,只要队列有值,就会弹出使用,没有值就无限等待,直到有值,就会弹出,celery的原理就是封装了发送任务至队列以及监控队列的脚本,不用开发工程师再去写blpop的脚本,直接配置呢就可以使用。大概原理就是这样。所以如果不用celery,也可以用最原始的方法实现异步消息的推送)

case1:delay()方式发送任务至队列

case1:

#注册任务

send_task.py

# -*- encoding:utf-8 -*-

import time

from celery import Celery

brokers = "redis://localhost:6379/1"

backend = "redis://localhost:6379/2"

celery = Celery('send_task',broker =brokers,backend=backend)

@celery.task

def add(x, y):

    time.sleep(20)

    return x +y

@celery.task

def multipy(a, b):

    return a*b

#任务调用

app.py

from send_task import add

if __name__ == '__main__':

    print "start task"

    add.delay(2,4)

    #将任务放置在队列中了,woker监控到队列有值之后,那么会自动取出任务执行

    print 'end task..'

疑问:

1.只指定了broker,(broker配置的地址仅到redis的某个库而已)但是没有具体指定队列?任务是发送至哪里了?worker监控哪个队列然后取任务执行的?是有默认的celery_task队列?

回答:celery有默认的队列,在设置了broker之后,add任务会默认发送至celery默认的default队列,worker会默认检测default队列有任务,并取出任务执行!当配置了backend之后,执行的结果存放在backend默认的default队列,当然也可以配置自己想要存放的队列

2.当未指定backend时,worker从broker-default队列取出“add”任务执行,任务结果会存放?为什么在worker服务启动界面还是可以看到返回的结果?如下:

[2018-11-21 16:08:07,469: INFO/MainProcess] Received task: send_task.add[1ac1d46e-35c1-4f77-80fc-df6252566417]

[2018-11-21 16:08:07,470: WARNING/Worker-1] action

[2018-11-21 16:09:07,470: WARNING/Worker-1] over

[2018-11-21 16:09:07,490: INFO/MainProcess] Task send_task.add[1ac1d46e-35c1-4f77-80fc-df6252566417] succeeded in 60.0209999084s: 6

回答:界面上显示了执行结果,表示broker的任务被取出执行了,如果没有执行,那说明可能卡在队列中了,与结果放置在backend中没有关系,即未设置backend就不会存储结果,配置了backend,就会存在对应的backend中

3.如果设置了backend,当add任务加入队列之后,worker取出并执行add方法,得到的结果应该在backend默认队列中,为什么去redis里面查看backend默认队列,没有结果?

回答:是有结果,

不过因为celery安全性,会给结果进行加密,直接在redis命令行通过get查看

case2:send_task()方式发送任务至队列

#发送结果至队列的启动函数

#app.py

# -*- encoding:utf-8 -*-

from send_task import app

if __name__ == '__main__':

    print "start task"

    app.send_task('send_task.add', queue='for_one',args=[56,311])

    app.send_task('send_task.multiply',queue='for_two',args=[55,2])

    #任务生产者,将add任务发送至for_add队列,args是该任务执行所需的参数

    """

    参数解析:

    ①任务路径及任务名称:给定该参数,会去这个路径下找该任务,并将该任务添加至后一个指定的队列;send_task.add:表示将哪个文件下的哪个任务放置队列中,如果给定一个错误的或者没有定义的任务,那么找不到,那就没有办法将这个任务放在队列中了

    ②队列名称:给定该参数,会将任务放置在该队列中,当worker启动中,会自动检测到该队列有任务并执行;

    ③任务所需参数:该参数执行,执行的任务所需的参数,即:add方法是需要两个参数的,如果缺少时,在添加任务至队列时,代码不会报错,在执行时报错

    """

    print 'end task..'

#send_task.py

#具体的任务函数

# -*- encoding:utf-8 -*-

from celery import Celery

app = Celery('task')

app.config_from_object('celeryconfig_send')

@app.task

def add(x, y):

    print "add"

    return x+y

@app.task

def multiply(a, b):

    print "multiply"

    return a * b

#celery配置文件

# -*- encoding:utf-8 -*-

from kombu import Queue

BROKER_URL = "redis://localhost:6379/1"

CELERY_RESULT_BACKEND= "redis://localhost:6379/2"

CELERY_TIMEZONE='Aisa/shanghai'

CELERY_DEFULT_QUEUE = 'default'

#创建任务队列

CELERY_QUEUES = (

    Queue('default', routing_key='default'),#不指定这行代码会报错

    Queue('for_one', routing_key='for_one'),

    Queue('for_two', routing_key='for_two')

)

#任务路由,相当于告诉worker,从哪里取获取要执行的哪个任务函数,当找不到任务对应的函数方法时,会报错

CELERY_ROUTES = {

    'send_task.tasks.add':{

        "queue":"for_one",

        "routing_key":"for_one"

    },

    'send_task.tasks.multiply': {

        "queue": "for_two",

        "routing_key": "for_two"

    }

}

学习代码已上传至github:https://github.com/zjojo/python_study/tree/master/A03_celery

猜你喜欢

转载自blog.csdn.net/Jolting/article/details/85758370
今日推荐