celery 使用
celery
1.celery介绍
celery能用来做什么:
1.异步任务
2.定时任务
3.延迟任务
1.1 理解celery的运行原理
1.可以不依赖任何服务器 通过自身命令 启动服务
2.celery服务为其他项目服务提供异步解决任务需求
注:会有两个服务同时运行 一个是项目服务 一个是celery服务 项目服务将需要异步处理的任务交给celery服务 celery就会在需要时异步完成项目的需求
项目服务正常服务 和selery服务互不打扰 当 项目服务需要异步操作时 selery服务会完成异步操作
1.2 celery架构(Broker、backend都用redis)
1.任务中间件 Broker(中间件)其他服务提交的异步任务 放在队列里
需要借助第三方: redis rabbitmq
2.任务执行单元 worker 真正执行异步任务的进程
celery提供的
3.结果存储 backend 结果存储 函数的返回结果 存到backend种
需要借助于第三方:redis mysql
1.3使用场景
异步执行:解决耗时任务
延迟执行:解决延迟任务
定时执行:解决周期任务
celery 不支持win 通过eventlet支持在win上运行
2.celery安装
# 安装---》安装完成,会有一个可执行文件 celery
pip install celery
celery 不支持win 通过eventlet支持在win上运行
win:pip install eventlet
3.celery包结构
1.project
├── celery_task # celery包
│ ├── __init__.py # 包文件
│ ├── celery.py # celery连接和配置相关文件,且名字必须交celery.py
│ # 所有任务函数
├── add_task.py # 添加任务
└── get_result.py # 获取结果
4.celery执行异步任务(快速使用)
1.新建一个celery_task--包
2.按照包结构创建py文件
3.celery.py
from celery import Celery
broker = 'redis://127.0.0.1:6379/1'
backend = 'redis://127.0.0.1:6379/2'
# app = Celery('test', broker=broker, backend=backend, include=['celery_task.user_task', 'celery_task.order_task'])
app = Celery('test', broker=broker, backend=backend, include=['celery_task.order_task', 'celery_task.user_task'])
4.order_task.py 添加任务
from celery_task.celery import app
import time
@app.task
def add(a, b):
print('-----', a + b)
time.sleep(2)
return a + b
5.user_task.py 添加项目任务
import time
from celery_task.celery import app
@app.task
def send_sms_ss(phone,code):
print("给%s发送短信成功,验证码为%s"%(phone,code))
time.sleep(3)
return True
6.lll_task.py 开启一个其他程序 提交项目任务
from celery_task.user_task import send_sms_ss
res = send_sms_ss.delay('123456789','66666') #立即异步执行
print(res)
'''
异步:
任务.delay
'''
7.终端 启动worker
celery -A selery_task worker -l info -P eventlet
8.worker会执行消息中间件的任务 把结果存起来
9.查看执行结果
from main import app
from celery.result import AsyncResult
id = '51611be7-4914-4bd2-992d-749008e9c1a6'
if __name__ == '__main__':
a = AsyncResult(id=id, app=app)
if a.successful(): # 执行完了
result = a.get() #
print(result)
elif a.failed():
print('任务失败')
elif a.status == 'PENDING':
print('任务等待中被执行')
elif a.status == 'RETRY':
print('任务异常后正在重试')
elif a.status == 'STARTED':
print('任务已经开始被执行')
5.celery执行延迟任务
lll_task.py
from datetime import datetime,timedelta
eta = datetime.utcnow()+timedelta(seconds=20)
res=send_sms_ss.apply_async(args=['123456789','66666'],eta=eta)
'''
延迟任务:
任务.apply_async(args=[],eta-eta) r
如果没有修改时区需要使用UTC时间
'''
6.celelry定时任务
需要启动beat和worker
beat --- 定时提交任务的进程 -- 配置在app.conf.beat_schedule的任务
worker --- 执行任务的
使用步骤:
#第一步:在celery中的py文件中写入
app.conf.timezone = 'Asia/Shanghai' #时区修改为上海
app.conf.enable_utc = False #是否使用UTC
#任务的定时配置
app.conf.beat_schedule = {
'send_sms': {
'task': 'celery_task.user_task.send_sms',
# 'schedule': timedelta(seconds=3), # 时间对象
# 'schedule': crontab(hour=8, day_of_week=1), # 每周一早八点
'schedule': crontab(hour=9, minute=43), # 每天9点43
'args': ('18888888', '6666'),
},
}
#第二步:启动beat
celery -A celery_task beat -l info
#第三步:启动worker
celery -A celery_task worker -l info -P eventlet
'''
注意:
1.启动命令的执行位置 如果是包结构 一定在包这一层
2.include = ['celery_task.order_task'],路径从包名下开始导入 因为我们在包这层执行的命令
'''
7.django中使用celery
如果在公司制作定时任务 还有一个更简单的框架
参考:https://blog.csdn.net/qq_41341757/article/details/118759836
使用步骤:
1.把咱们写的包复制到项目目录下
-luffy_lzy
-celery_task #包路径
-luffy_lzy #源代码路径 小路飞
2.在使用提交异步任务的位置 导入使用即可
在试图函数中使用 导入任务
任务.delay() #提交任务
3.启动worker 如果有定时任务 启动beat
4.等待任务被worker执行
5.在视图函数中 查询任务执行的结果
7.1秒杀功能
逻辑分析:
1.前端秒杀按钮 用户点击 --- 发送ajax请求
2.视图函数 -- 提交秒杀任务 -- 借助于celery 提交到中间件中
3.当次秒杀的请求 就回去了 携带者任务id号在前端
4.前端开启定时任务 每隔3秒 带着任务 向后端发送请求 查看是否秒杀成功
5.后端的情况
1.任务还在等待被执行 --- 返回给前端 前端继续没隔3s发送一次请求
2.任务执行完了 秒杀成功 ---返回给前端 恭喜秒杀成功 --关闭前端定时器
3.任务执行完了 秒杀失败 ---返回给后端 秒杀失败--关闭前端定时器
7.2视图
#### 秒杀逻辑,CBV
from rest_framework.viewsets import ViewSet
from celery_task.order_task import sckill_task
from celery_task.celery import app
from celery.result import AsyncResult
class SckillView(ViewSet):
@action(methods=['GET'], detail=False)
def sckill(self, request):
a = request.query_params.get('id')
# 使用异步,提交一个秒杀任务
res = sckill_task.delay(a)
return APIResponse(task_id=res.id)
@action(methods=['GET'], detail=False)
def get_result(self, request):
task_id = request.query_params.get('task_id')
a = AsyncResult(id=task_id, app=app)
if a.successful():
result = a.get()
if result:
return APIResponse(msg='秒杀成功')
else:
return APIResponse(code=101, msg='秒杀失败')
elif a.status == 'PENDING':
print('任务等待中被执行')
return APIResponse(code=666, msg='还在秒杀中')
7.3 任务 order_task.py
# 秒杀任务
import random
import time
@app.task
def sckill_task(good_id):
# 生成订单,减库存,都要在一个事务中
print("商品%s:秒杀开始" % good_id)
# 这个过程,可能是1,2,3s中的任意一个
time.sleep(random.choice([6, 7, 9]))
print('商品%s秒杀结束' % good_id)
return random.choice([True, False])
7.4前端 Sckill.vue
<template>
<div>
<button @click="handleSckill">秒杀</button>
</div>
</template>
<script>
import Header from '@/components/Header';
import Banner from '@/components/Banner';
import Footer from '@/components/Footer';
export default {
name: 'Sckill',
data() {
return {
task_id: '',
t: null
}
},
methods: {
handleSckill() {
this.$axios.get(this.$settings.BASE_URL + '/user/sckill/sckill/?id=999').then(res => {
this.task_id = res.data.task_id
this.t = setInterval(() => {
this.$axios.get(this.$settings.BASE_URL + '/user/sckill/get_result/?task_id=' + this.task_id).then(res => {
if (res.data.code == 666) {
//如果秒杀任务还没执行,定时任务继续执行
console.log(res.data.msg)
} else {
// 秒杀结束,无论成功失败,这个定时任务都结束
clearInterval(this.t)
this.t = null
this.$message(res.data.msg)
}
})
}, 2000)
}).catch(res => {
})
}
}
}
</script>
7.5 django中使用celery
-1 把咱们写的包,复制到项目目录下
-luffy_api
-celery_task #celery的包路径
celery.py # 一定不要忘了一句话
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')
-luffy_api #源代码路径
-2 在使用提交异步任务的位置,导入使用即可
-视图函数中使用,导入任务
-任务.delay() # 提交任务
-3 启动worker,如果有定时任务,启动beat
-4 等待任务被worker执行
-5 在视图函数中,查询任务执行的结果
# 重点:celery中使用djagno,有时候,任务中会使用django的orm,缓存,表模型。。。。一定要加
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')
3.轮播图接口加缓存
1.轮播图接口请求来了 先去缓存去看 如果有 直接返回
2.如果没有 查数据库 然后把轮播图数据放到Redis中 缓存起来
改接口
#加入缓存的轮播图接口
class BannerView(GenericViewSet,ListModelMixin):
queryset = Banner.objects.filter(is_delete=False, is_show=True).order_by('orders')
serializer_class = BannerSerializer
def list(self, request, *args, **kwargs):
banner_list = cache.get('banner_list')
#查看缓存有没有数据 如果没有再走数据库
if banner_list:
return APIResponse(data=banner_list)
else: #数据库
res = super().list(request, *args, **kwargs)
cache.set('banner_list',res.data)
return APIResponse(data=res.data)
# {code:100,msg;成功,data=[{},{}]}
8.双写一致性
加入缓存后 缓存中有数据 先去缓存拿 但是如果mysql中数据变了 缓存不会自动变化 出现数据不一致问题 -- mysql和缓存数据库不一致
双写一致性
写入mysql redis没动 数据不一致存在问题
如何解决
1.修改数据 删除缓存
2.修改数据 更新缓存
3.定时更新缓存 --- 实时性差
#定时任务 :celery
9.首页轮播图定时更新
第一步:在celery配置定时任务
app.conf.beat_schedule = {
'update_banner': {
'task': 'celery_task.home_task.update_banner',
'schedule': timedelta(seconds=3), # 时间对象
},
}
第二步:启动worker 启动beat
# update_banner任务的代码
from home.models import Banner
from home.serializer import BannerSerializer
from django.core.cache import cache
from django.conf import settings
@app.task
def update_banner():
# 只要这个任务一执行,就更新轮播图的缓存
banners = Banner.objects.all().filter(is_delete=False, is_show=True).order_by('orders')
ser = BannerSerializer(instance=banners, many=True)
for item in ser.data:
item['image'] = settings.BACKEND_URL + item['image']
cache.set('banner_list', ser.data) # 会出问题,轮播图地址显示不全
return True
celery 使用的更多相关文章
- 异步任务队列Celery在Django中的使用
前段时间在Django Web平台开发中,碰到一些请求执行的任务时间较长(几分钟),为了加快用户的响应时间,因此决定采用异步任务的方式在后台执行这些任务.在同事的指引下接触了Celery这个异步任务队 ...
- celery使用的一些小坑和技巧(非从无到有的过程)
纯粹是记录一下自己在刚开始使用的时候遇到的一些坑,以及自己是怎样通过配合redis来解决问题的.文章分为三个部分,一是怎样跑起来,并且怎样监控相关的队列和任务:二是遇到的几个坑:三是给一些自己配合re ...
- tornado+sqlalchemy+celery,数据库连接消耗在哪里
随着公司业务的发展,网站的日活数也逐渐增多,以前只需要考虑将所需要的功能实现就行了,当日活越来越大的时候,就需要考虑对服务器的资源使用消耗情况有一个清楚的认知. 最近老是发现数据库的连接数如果 ...
- celery 框架
转自:http://www.cnblogs.com/forward-wang/p/5970806.html 生产者消费者模式 在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据 ...
- celery使用方法
1.celery4.0以上不支持windows,用pip安装celery 2.启动redis-server.exe服务 3.编辑运行celery_blog2.py !/usr/bin/python c ...
- Celery的实践指南
http://www.cnblogs.com/ToDoToTry/p/5453149.html Celery的实践指南 Celery的实践指南 celery原理: celery实际上是实现了一个典 ...
- Using Celery with Djang
This document describes the current stable version of Celery (4.0). For development docs, go here. F ...
- centos6u3 安装 celery 总结
耗时大概6小时. 执行 pip install celery 之后, 在 mac 上 celery 可以正常运行, 在 centos 6u3 上报错如下: Traceback (most recent ...
- celery 异步任务小记
这里有一篇写的不错的:http://www.jianshu.com/p/1840035cb510 自己的"格式化"后的内容备忘下: 我们总在说c10k的问题, 也做了不少优化, 然 ...
- Celery 框架学习笔记
在学习Celery之前,我先简单的去了解了一下什么是生产者消费者模式. 生产者消费者模式 在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是 ...
随机推荐
- ARC(Automatic Reference Counting)自动引用计数 unowned、weak 使用区别
自动引用计数 引用类型(类.函数.闭包) 当声明一个变量指向某个引用类型时 当前引用类型的引用计数就会加1 当变量不指向该类型时 引用类型就会 -1 当引用计数为0时 当前引用类型就会被系统回收 i ...
- Unity 纯C# 完成 APK从下载到 自安装
最简单的就是用androidStudio 进行编辑,打个aar 包,在Unity中调用方法,很便捷以下内容均转载Unity论坛,Android API24版本下可用,android API 24以上版 ...
- 个人js基础知识及看js高级程序设计查漏 汇总
1.事件循环机制 js单线程操作. 1>主线程读取js代码 ,此时为同步环境,形成相应的堆和执行栈. 2>主线程遇到异步任务,指给对应的异步进程处理. 3>异步进程处理完毕后,将相应 ...
- js模块化 CommonJS和AMD/CMD ES6模块化
ES6之前已经出现了js模块方案,有CommonJS和AMD规范.commonjs实现同步加载应用于服务器,如nodejs.AMD为异步加载应用于浏览器,如requirejs. ES6在语言层面上模块 ...
- 从零搭建php环境-php8-扩展-redis
一.下载1.https://pecl.php.net/get/redis-5.3.2.tgz下载到本地,文件传输上传到 /usr/local/src/2.wget -P /usr/local/src/ ...
- JAVA第六七八次大作业
21201411-李英涵 前言:这几次的作业较为简单,主要思路就是利用正则表达式来过滤掉不需要的信息. 题量设置较为合理,比之前的多边形好做一些,应该是老师为了捞起来 ...
- PHP、Navicat安装
一.PHPStudy小皮面板:https://public.xp.cn/upgrades/phpStudy_64.zip 下载完成后解压后双击 点击立即安装 安装完成 启动MySQL,Nginx(my ...
- 获取指定字符串第n次出现的位置索引
returnIndex(str,cha,num){ var x=str.indexOf(cha); for(var i=0;i<num;i++){ x=str.indexOf(cha,x+1); ...
- Android studio应用
菜单的使用 public class FirstActivity extends AppCompatActivity { @Override protected void onCreate(Bundl ...
- 图论之最小生成树问题(kruskal)
最近有几位同学催我更新,于是来摸摸鱼,来讲一下最小生成树问题. 所谓最小生成树(MST),就是在一张无向带权图中的一棵经过所有节点,边权和最小的一棵树.在实际生活中,可以运用于城镇之间的修路上. 对于 ...