celery介绍
# celery是什么?
分布式异步任务框架:第三方框架,celery翻译过来是芹菜,吉祥物就是芹菜
项目中使用异步任务的场景,可以使用它
之前做异步,如何做? 异步发送短信--->开启多线程--->不便于管理
# celery有什么作用?
-执行异步任务
-执行延迟任务
-执行定时任务
# celery原理
1)可以不依赖任何服务器,通过自身命令,启动服务
2)celery服务为为其他项目服务提供异步解决任务需求的
注:会有两个服务同时运行,一个是项目服务,一个是celery服务,项目服务将需要异步处理的任务交给celery服务,celery就会在需要时异步完成项目的需求
人是一个独立运行的服务 | 医院也是一个独立运行的服务
正常情况下,人可以完成所有健康情况的动作,不需要医院的参与;但当人生病时,就会被医院接收,解决人生病问题
人生病的处理方案交给医院来解决,所有人不生病时,医院独立运行,人生病时,医院就来解决人生病的需求
django如果不用异步,正常运行即可,如果想做异步,就借助于 celery来完成
# celery架构
-broker:消息中间件,任务中间件(消息队列:redis,rabbitmq)
django要做异步,提交任务到 任务中间件中(redis),存储起来
Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ, Redis等等
-worker:任务执行者,任务执行单元
不停的从任务中间件中取任务,执行
Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中
-banckend:结果存储,任务结果存储
把任务执行结果(函数返回值),存放到结果存储中(redis)
用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括AMQP, redis等
### 任务中间件:redis
### 结果存储:redis
celery的快速使用
注意:celery本身是不支持win的,在win上面使用需要借助于第三方
# 安装
pip install celery
# main.py
import time
from celery import Celery
broker = 'redis://127.0.0.1:6379/1' # 消息中间件 redis
backend = 'redis://127.0.0.1:6379/2' # 结果存,用redis
#1 实例化得到一个对象
app = Celery("app", broker=broker, backend=backend)
#2 编写任务,必须用app.task 装饰,才变成了celery的任务
@app.task
def send_sms():
time.sleep(2)
print("短信发送成功")
return "手机号发送成功"
#3 提交任务使用别进程
from main import send_sms
res = send_sms.delay()
print(res)
### 4 启动worker--->可以在3之前
# windows:
pip3 install eventlet
# 切换到含有app的的文件夹下
celery -A main worker -l info -P eventlet
# mac linux
# celery -A main worker -l info
### 5 worker就会执行任务,把执行的结果,放到结果存储中
### 6 查看结果
from celery.result import AsyncResult
from main import app
id = '92987636-ae9e-4be9-828b-8c2d10fe066a'
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('任务已经开始被执行')
补充单例
什么是单例模式?单例模式是指:保证一个类仅有一个实例,并提供一个访问它的全局访问点
# 线程1 执行:
cursor.excute('select * from user')
# 线程2执行
cursor.excute('select * from books')
# 线程1 执行
cursor.fetchAll() # 拿出查询到的数据
# django ,每个线程,一个连接对象--->连接池
1.使用模块
其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc
文件,当第二次导入时,就会直接加载 .pyc
文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:
mysingleton.py
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
将上面的代码保存在文件 mysingleton.py
中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象
from a import singleton
2.使用装饰器
def Singleton(cls):
instance = None
def _singleton(*args, **kargs):
nonlocal instance
if not instance:
instance = cls(*args, **kargs)
return instance
return _singleton
@Singleton
class A(object):
def __init__(self, x=0):
self.x = x
a1 = A(2)
a2 = A(3)
print(a1.x)
print(a2.x)
print(a1 is a2)
3.使用类方法
class Singleton(object):
_instance=None
def __init__(self):
pass
@classmethod
def instance(cls, *args, **kwargs):
if not cls._instance:
cls._instance=cls(*args, **kwargs)
return cls._instance
a1=Singleton.instance()
a2=Singleton().instance()
print(a1 is a2)
4.基于new方法实现
class Singleton(object):
_instance=None
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls)
return cls._instance
obj1 = Singleton()
obj2 = Singleton()
print(obj1 is obj2)
5.基于metaclass方式实现
class SingletonType(type):
_instance=None
def __call__(cls, *args, **kwargs):
if not cls._instance:
# cls._instance = super().__call__(*args, **kwargs)
cls._instance = object.__new__(cls)
cls._instance.__init__(*args, **kwargs)
return cls._instance
class Foo(metaclass=SingletonType):
def __init__(self,name):
self.name = name
obj1 = Foo('name')
obj2 = Foo('name')
print(obj1.name)
print(obj1 is obj2)