诚意
诚意如你,当一诚的态度对待

导航

 

请先安装并开启redis

一:celery介绍

Celery 是基于Python实现的第三方组件, 用于执行异步、定时、周期任务的分布式任务队列
其结构的组成是由
    1.用户任务 app  (老板、发布任务
    2.管道 broker 用于存储任务 官方推荐 redis rabbitMQ  / backend 用于存储任务执行结果的(记录任务 broker 、 任务返回记录backend
    3.员工 worker   (执行任务、反馈结果

 

二:celery应用

pip install celery

开启redis----》存储任务、任务返回记录

1:老板发布任务--app创建任务放到broker里

s1.py
from celery import Celery
import time

#创建一个Celery实例,这就是我们用户的应用app
my_task = Celery("tasks", broker="redis://127.0.0.1:6379", backend="redis://127.0.0.1:6379")

# 为应用创建任务,func1,发布任务
@my_task.task
def func1(x, y):
    time.sleep(15)
    return x + y

 

 

2:雇佣员工

后台cmd开启任务

(venv) E:\python\代码\Flas\celer>Celery worker -A s1 -l INFO -P eventlet -c  6             #-A:可以执行s1文件下所有任务    INFO:运行级别   -c表示创建worker数量   

  

  出现ValueError错误,因为celery对Windows系统提供的支持不好,需要安装evenlet

     

 

 

3:执行任务

s2.py
from s1 import func1

# 将任务交给Celery的Worker执行
res = func1.delay(2,4)

#返回任务ID
print(res.id)

 

4:在backend中获取任务返回结果

s3.py
from celery.result import AsyncResult
from s1 import my_task

# 异步获取任务返回值
async_task = AsyncResult(id="31ec65e8-3995-4ee1-b3a8-1528400afd5a",app=my_task)

# 判断异步任务是否执行成功
if async_task.successful():
    #获取异步任务的返回值
    result = async_task.get()
    print(result)
else:
    print("任务还未执行完成")

 

三:案例

1:爬虫-异步

import requests,os,time
from celery import Celery
my_task = Celery("task",broker="redis://127.0.0.1:6379",backend="redis://127.0.0.1:6379")


base_url = "http://audio.xmcdn.com/"
url = "http://m.ximalaya.com/m-revision/page/track/queryTrackPage/%s"


@my_task.task
def xiaopapa(c):
    audio_id = c.rsplit("/",1)[-1]

    res = requests.get(url%(audio_id))

    res_dict = res.json().get("data").get("trackDetailInfo").get("trackInfo")

    cover_url = base_url + res_dict.get("cover")
    audio_url = res_dict.get("playPath")
    audio = requests.get(audio_url)
    cover = requests.get(cover_url)

    from uuid import uuid4

    filename = uuid4()
    image = os.path.join(f"{filename}.jpg")
    music = os.path.join(f"{filename}.mp3")

    with open(music,"wb") as f:
        f.write(audio.content)

    with open(image,"wb") as cf:
        cf.write(cover.content)

    time.sleep(1)

    return filename
发布任务

 

from caijiTools import xiaopapa

content_list = ["/ertong/424529/7713660","/ertong/424529/7713675",
                "/ertong/424529/7713577","/ertong/424529/7713571",
                "/ertong/424529/7713546","/ertong/424529/7713539"]

for i in content_list:
    res = xiaopapa.delay(i)
    print(res)
执行任务

 

 

2:定时任务

发布任务

from celery import Celery

my_task = Celery("task",broker="redis://127.0.0.1:6379",backend='redis://127.0.0.1:6379')

@my_task.task
def my_func1(x,y):
    return "my_func1"


@my_task.task
def my_func2(x,y):
    return "my_func2"

@my_task.task
def my_func3(x,y):
    return "my_func3"

 

雇佣员工

(venv) E:\python\代码\Flas\celer>Celery worker -A s1 -l INFO -P eventlet -c 6

执行任务

from s1 import my_func1,my_func2,my_func3
import time,datetime

tp = time.time()
# 将当前的东八区时间改为 UTC时间 注意这里一定是UTC时间,没有其他说法
utc_time = datetime.datetime.utcfromtimestamp(tp)
# 为当前时间增加 10 秒
add_time = datetime.timedelta(seconds=30)
utc_time = utc_time + add_time

# action_time 就是当前时间未来30秒之后的时间
res = my_func1.apply_async(args=(2,3),eta=utc_time) 

print(res)

 

可以在backend中检查

# 异步获取任务返回值
async_task = AsyncResult(id='f2c6e1f2-e412-4729-b37f-252b44048577',app=my_task)

# 判断异步任务是否执行成功
if async_task.successful():
    # 获取异步任务的返回值
    result = async_task.get()
    print(result)
else:
    print("任务还未执行完成")

 

 

3:周期任务 

 任务配置

from celery import Celery
from celery.schedules import crontab

my_task = Celery("task",broker="redis://127.0.0.1:6379",
                 backend='redis://127.0.0.1:6379',
                 include=['task_one','task_two'])  #include:加载任务

#我要对beat任务生产做一个配置,这个配置的意思就是每10秒执行一次Celery_task.task_one任务参数是(10,10)
my_task.conf.beat_schedule={
    "each10s_task":{
        "task":"task_one.my_func1",#要执行的任务
        "schedule":10, # 每10秒钟执行一次
        "args":(10,10)#参数
    },
    # "each1m_task": {
    #     "task": "Celery_task.task_one.one",
    #     "schedule": crontab(minute=1), # 每一分钟执行一次
    #     "args": (10, 10)
    # },
    # "each24hours_task": {
    #     "task": "Celery_task.task_one.one",
    #     "schedule": crontab(hour=24), # 每24小时执行一次
    #     "args": (10, 10)
    # }

}

#以上配置完成之后,还有一点非常重要
# 不能直接创建Worker了,因为我们要执行周期任务,所以首先要先有一个任务的生产方
# celery beat -A 文件名    #会读上面的配置
# celery worker -A 文件名 -l INFO -P eventlet

 

 

task_one.py(具体任务)

from s1 import my_task

@my_task.task
def my_func1(x,y):
    return "my_func1"

@my_task.task
def my_func2(x,y):
    return "my_func2"


(venv) E:\python\代码\Flas\celer>Celery beat -A s1 #读周期任务的配置

  (venv) E:\python\代码\Flas\celer>Celery worker -A s1 -l INFO -P eventlet -c 6  #雇佣员工

 

  创建worker之后,每10秒就会由beat创建一个任务给Worker去执行

 

 

执行任务。。。。

之后你会发现自动生成的文件

 

四:celery目录

在实际项目中我们应用Celery是有规则的

要满足这样的条件才可以哦,目录Celery_task这个名字可以随意起,但是一定要注意在这个目录下一定要有一个celery.py这个文件

 

from celery import Celery

celery_task = Celery("task",
                     broker="redis://127.0.0.1:6379",
                     backend="redis://127.0.0.1:6379",
                     include=["Celery_task.task_one","Celery_task.task_two"])
# include 这个参数适用于寻找目录中所有的task

celery.py
celery.py
from .celery import celery_task
import time

@celery_task.task
def one(x,y):
    time.sleep(5)
    return f"task_one {x+y}"

task_one
task_one
from .celery import celery_task
import time

@celery_task.task
def two(x,y):
    time.sleep(5)
    return f"task_two {x+y}"

task_two
task_two

 

 

这样Celery项目目录结构就已经做好了然后再 my_celery中调用

 

from Celery_task.task_one import one
from Celery_task.task_two import two
 
one.delay(10,10)
two.delay(20,20)

PS:启动Worker的时候无需再使用文件启动,直接启动你的Celery_task目录就行了
celery worker -A Celery_task -l INFO -P eventlet
这样celery就可以自动的去检索当前目录下所有的task了,通过Include这个参数逐一去寻找

 


参考资料:

  

Celery 官方文档英文版http://docs.celeryproject.org/en/latest/index.html

Celery 官方文档中文版:http://docs.jinkan.org/docs/celery/

 

posted on 2019-02-18 15:31  诚意  阅读(284)  评论(0)    收藏  举报