1.缓存

  当一些数据需要固定地且频繁访问数据库时,需要使用到接口缓存。

  以轮播图为例,每个用户都会访问首页,首页的轮播图长时间不会改变,所以可以使用cache,将固定数据保存到缓存中(redis),第二次调用数据库的时候,就可以从缓存中调用数据,使得并发量增加,保护数据库。

  但是一直访问缓存,数据库改变了数据,那么本来的页面就不会被改变。所以要使用celery定时地访问数据库,修改数据。

2.celery的使用场景

  celeryd使用场景除了运行定时任务之外们还可以执行异步任务。

  在官网可以找到开发文档:

Celery 官网:http://www.celeryproject.org/

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

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

  每一个celery都由三部分组成:

  1.消息中间件

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

  2.任务执行单元

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

  3.任务结果存储

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

三。celery的装配

  下载celery

pip install celery

消息中间件:RabbitMQ/Redis

app=celery.Celery('任务名', broker='xxx', backend='xxx', include=['xxx', 'xxx'])

  包架构封装

project
├── celery_task # celery包
│ ├── __init__.py # 包文件
│ ├── celery.py # celery连接和配置相关文件,且名字必须交celery.py
│ └── tasks.py # 所有任务函数
├── add_task.py # 添加任务
└── get_result.py # 获取结果

  将celery_task包放到大项目下,这个包名可以随意,但是启动任务的时候需要用到,

  其中的celery必须使用该名字,

  启动celery的语句如下:

# 2)启动celery(app)服务:
# 非windows
# 命令:celery worker -A celery_task -l info
# windows:
# pip3 install eventlet
# celery worker -A celery_task -l info -P eventlet # 3)添加任务:手动添加,要自定义添加任务的脚本,右键执行脚本 # 4)获取结果:手动获取,要自定义获取任务的脚本,右键执行脚本

  如果需要自动执行添加任务,需要启动一个添加任务的服务。

# 命令: celery beat -A celery_task -l info

  celery_tesk时celery总文件夹。

  启动worker就可以随时从任务列表中获取任务执行。

  1.celery

  celery中需要配置django相关的环境以及celery的环境。


import os,django
# import sys
# sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Wechatshop.settings")
django.setup()
from celery import Celery

broker = 'redis://127.0.0.1:6379/1'
backend = 'redis://127.0.0.1:6379/2'
app = Celery(broker=broker, backend=backend, include=['celery_task.tasks']) # 时区
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False # 任务的定时配置
from datetime import timedelta
from celery.schedules import crontab
app.conf.beat_schedule = {
'low-task': { # 新的任务名
'task': 'celery_task.tasks.low',# 任务源
'schedule': timedelta(seconds=3),# 定时时间
# 'schedule': crontab(hour=8, day_of_week=1), # 每周一早八点
'args': (300, 150), # 定时参数
}
}

  如果需要添加定时任务,需要做以上配置

  2.tasks

  任务源,文件名可以改变,但是其他地方调用的时候需要改变。

  在任务函数之气那需要调用语法糖。

from .celery import app
import time
@app.task
def add(n, m):
print(n)
print(m)
time.sleep(10)
print('n+m的结果:%s' % (n + m))
return n + m @app.task
def low(n, m):
print(n)
print(m)
print('n-m的结果:%s' % (n - m))
return n - m from home.models import Banner
from settings.const import BANNER_COUNT # 轮播图最大显示条数
from home.serializers import BannerModelSerializer
from django.core.cache import cache
@app.task
def update_banner_list():
# 获取最新内容
banner_query = Banner.objects.filter(is_delete=False, is_show=True).order_by('-orders')[:BANNER_COUNT]
# 序列化
banner_data = BannerModelSerializer(banner_query, many=True).data
for banner in banner_data:
banner['image'] = 'http://127.0.0.1:8000' + banner['image']
# 更新缓存
cache.set('banner_list', banner_data)
return True

  3.add_task

  当需要添加任务的时候,直接在需要添加任务的地方调用任务文件夹下的任务名,执行对于的函数:

from celery_task import tasks
# 添加立即执行任务
t1 = tasks.add.delay(10, 20)
t2 = tasks.low.delay(100, 50)
print(ti.id)

  返回值为id,delay代表添加及时任务。括号中的时任务需要的参数。

  添加定时任务需要在celery中配置。在启动该任务的时候,需要beat的帮助才能定时地添加任务,启动任务。

# 命令: celery beat -A celery_task -l info

  添加延时任务。

  需要设定eta_second,将时间转换为celery需要的时间格式,单位为秒

# 添加延迟任务
from datetime import datetime, timedelta
def eta_second(second):
ctime = datetime.now()
utc_ctime = datetime.utcfromtimestamp(ctime.timestamp())
time_delay = timedelta(seconds=second)
return utc_ctime + time_delay tasks.low.apply_async(args=(200, 50), eta=eta_second(10))

  关键函数为apply_async.

  扩展:

  动态添加定时任务,可以使用redis后端链接mysql,参考项目。

https://github.com/sibson/redbeat

  

  创建一个文件夹如上,celery中是框架内容和环境,tasks则需要编写语法糖装饰过的函数:

from .celery import app
import time
@app.task
def add(n, m):
print(n)
print(m)
time.sleep(10)
print('n+m的结果:%s' % (n + m))
return n + m

  如果需要在django中运行,需要引入django的环境。

  启动celey:

  需要安装一个线程相关的模块

pip install eventlet

  启动work

celery worker -A celery_task -l info -P eventlet

  一般在项目目录下启动,如果启动失败,就指定到celery的文件夹:celey_task.celery

  启动beat:

celery beat -A celery_task -l info

  注意环境的搭建路径

  1.及时任务的添加:

from celery_task.tasks import test
t1 = test.delay()

  括号中传递的是即使任务函数的参数

  2.延时任务的添加:

from datetime import datetime, timedelta
def eta_second(second):
ctime = datetime.now()
utc_ctime = datetime.utcfromtimestamp(ctime.timestamp())
time_delay = timedelta(seconds=second)
return utc_ctime + time_delay tasks.low.apply_async(args=(200, 50), eta=eta_second(10))

  apply_async的第一个参数是运行函数的参数,第二个参数则是时间类型的时间,需要给指定的运行时间。

  3.定时任务:

# 任务的定时配置
from datetime import timedelta
from celery.schedules import crontab
app.conf.beat_schedule = {
'printnb-task': {
'task': 'celery_task.tasks.printnb',
'schedule': timedelta(seconds=10), # 配置任务时间
# 'schedule': crontab(hour=8, day_of_week=1), # 每周一早八点
'args': (), # 执行任务的参数
}
}

  其中,任务函数的返回值可以是任意的。

  获取函数结果:

from celery_task.celery import app

from celery.result import AsyncResult

id = '21325a40-9d32-44b5-a701-9a31cc3c74b5'
if __name__ == '__main__':
async = AsyncResult(id=id, app=app)
if async.successful():
result = async.get()
print(result)
elif async.failed():
print('任务失败')
elif async.status == 'PENDING':
print('任务等待中被执行')
elif async.status == 'RETRY':
print('任务异常后正在重试')
elif async.status == 'STARTED':
print('任务已经开始被执行')

  其中

as1 = AsyncResult(id=id,app=app)

  as1打印出来的就是任务id,开发者可以根据任务id(as1.id)

  可以根据启动任务时获取的返回值对象获取id,再使用AsyncResult生成返回对象。

  async.successful():

  检测任务是否完成,返回布尔值。

  async.failed():

  检测任务是否失败,返回布尔值。

  result = async.get()

  获取任务执行之后的结果就是任务函数的返回值

  async.status

  返回任务的状态。

day82_10_31celery的使用的更多相关文章

随机推荐

  1. June 03rd, 2019. Week 23rd, Monday

    There is no shame in hard work. 努力从来不丢人. Stop complaining about the current work arrangements, just ...

  2. 算法问题实战策略 FENCE

    地址 https://algospot.com/judge/problem/read/FENCE 开始考虑暴力遍历 #include <iostream> #include <str ...

  3. 普通结果集ResultSet和离线结果集RowSet(四)

    数据库的查询操作会得到一系列数据,JDBC API也提供了相关对象来接收查询结果集. 一.ResultSet java.sql.ResultSet接口表示数据库查询的结果集. JDBC提供以下连接方法 ...

  4. python第一次作业-Numpy练习

    1.创建一个边界值为1而内部都是0的数组,图例如下:[提示:]解此题可以先把所有值都设置为1,这是大正方形:其次,把边界除外小正方形全部设置为0.本题用到numpy的切片原理.多维数组同样遵循x[st ...

  5. WEB-INF文件夹作用

    WEB-INF是Java的WEB应用的安全目录,客户端无法访问,只能通过服务端访问,从而实现了代码的安全.在WEB-INF中主要是系统运行的配置信息和环境 主要有classes.config.lib文 ...

  6. 运行时报:尝试加载 Oracle 客户端库时引发 BadImageFormatException,如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题

    运行环境为: Windows Server2012 Oracle11g  32位数据库+客户端 IIS发布后提示错误信息: “尝试加载 Oracle 客户端库时引发 BadImageFormatExc ...

  7. WPF ListBox 隐藏滑块

    <ListBox ScrollViewer.VerticalScrollBarVisibility = "Disabled"; </ListBox>

  8. 对Python中函数参数类型及排序问题,三个方面的总结

    Python中函数的参数问题有点复杂,主要是因为参数类型问题导致的情况比较多,下面来分析一下. 参数类型:缺省参数,关键字参数,不定长位置参数,不定长关键字参数. 其实总共可以分为 位置参数和关键字参 ...

  9. C#中巧用Lambda进行数据的筛选查询等处理

    场景 有一个Record对象的list,如果要根据其某个属性CycleIndex进行分组,类似于sql的group by分组查询. 如果要在这个这个list中查找出符合某种条件的数据,类似于sql的w ...

  10. VUE组内培训

    最近去参加了一个外部VUE的周末培训,加上自己比较感兴趣所以对这项很热的前端框架做了点学习,顺便给组内同事做个简单的分享,希望下次有项目可以使用上- VUE的语法教程网上很多我就不一一列举,截图放一下 ...