单例

单例模式

单例是23种设计模式的一种,最简单的一种

https://www.cnblogs.com/liuqingzheng/p/10038958.html

什么是单例模式?

单例模式指的是:保证一个类仅有一个实例,并提供一个访问它的全局访问点

线程1 执行:

cursor.excute('select * from user')

线程2执行:

cursor.excute('select * from books')

线程1 执行

cursor.fetchAll() # 本来想取线程1的数据,但是拿出查询到的数据得到线程2的数据

综上,所以django ,每个线程,一个连接对象,不然就会数据错乱---》 有了连接池

使用单例五种方法

方法1、使用模块

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

通俗来说,当第一次导入后会生成一个文件pyc,当后续再次使用这个模块导入时,就不会再执行代码了,会从pyc中直接拿出来用。

mysingleton.py

class Singleton(object):
    def foo(self):
        pass
singleton = Singleton()

将上面的代码保存在文件 mysingleton.py 中,要使用时,直接在其他文件中导入此文件中的对象,这个对象即是单例模式的对象

from mysingleton import singleton

 

方法2、使用装饰器

之前学的 装饰器,都是用来装饰 函数 ,装饰器可以用来装饰类

 执行结果为True

 

单例3、使用类方法

 

方法4、使用 __new__

通俗的讲解Python中的__new__()方法-CSDN博客

__init__ 和 __new__ 区别是什么    __new__ 相当于一个人出生,啥也没有,__init__ 相当于给他穿衣服等。
1 类()--->触发类中的__init__--->对象已经创建出来了,不能拦截住,做成单例了
2 类()--->触发类中的__new__--->真正的创建对象,判断之前有没有创建过,如果创建过,直接返回
3 懂了元类---》类()--->触发元类的 __call__--->判断之前有没有创建过,如果创建过,直接返回

 

方法5、通过元类,基于metaclass方式实现

元类:产生这个对象的类叫元类

触发元类的 __call__--->判断之前有没有创建过,如果创建过,直接返回

 

redis其他操作

'''
delete(*names)
exists(name)
keys(pattern='*')
expire(name ,time)
rename(src, dst)
move(name, db))
randomkey()
type(name)
'''
可能会问到的:
# redis的key值,最大可以是多少? 最大不超过512M 一般 1KB # redis的value值,最大可以是多少? 最大不超过512M

 

redis管道

事务四大特征

  原子性:要么都成功,要么都失败

  一致性:数据前后要一致

  隔离性:多个事务之间相互不影响

  持久性:事务一旦完成,数据永久改变

 

关系型数据库支持事务

mysql  关系型数据库(oracle,sqlserver,postgrasql)

非关系型数据(no sql):redis,mongodb,clickhouse,infludb,elasticsearch,hadoop。。。

 

redis 有没有事务?没有专门的事物,但是通过别的方式,可以实现事务的几个特性,所以咱们认为它具备事务

  redis要支持事务,要完成事务的几大特性,需要使用管道来支持

  单实例redis是支持管道的

  集群模式下,不支持管道,就不支持事务

没有管道的情况下:

 有管道的情况下:

 

django中使用redis

通用方案

# 写一个池
import redis

POOL = redis.ConnectionPool(max_connections=20)

# 在要使用的地方,导入使用即可
def redis_demo(requset):
    conn = redis.Redis(connection_pool=POOL, decode_responses=True)
    res = conn.incrby('count')
    print(res)

    return HttpResponse(f'您是我们第:{res}个用户')

 

第三方模块

django-redis ---》配置文件中配置即可

pip install django-redis

配置文件配置

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
            # "PASSWORD": "123",
        }
    },
}

在使用的位置,导入使用

from django_redis import get_redis_connection
def redis_demo(requset):
    conn = get_redis_connection()
    res = conn.incrby('count')
    print(res)

    return HttpResponse(f'您是我们第:{res}个用户')

 

django缓存

redis数据存在内存中,取放速度快,非常适合做缓存

本来数据在mysql中,每次都查询,速度慢---》把查询出来的数据,暂时存储到redis(缓存),下次请求再来,直接从redis中拿,速度就会很快

 

django中如何使用缓存

  配置文件配置(缓存位置:内存,文件中,redis中)

CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
                "CONNECTION_POOL_KWARGS": {"max_connections": 100}
                # "PASSWORD": "123",
            }

  把数据放到缓存中(放到redis中)

from django.core.cache import cache
cache.set(key,value可以是任意类型,过期时间)

redis只支持5大数据类型,可以放python的任意类型

本质:pickle序列化---》bytes格式---》以redis字符串的形式放在了redis中

cache.get(key)

后期咱么在项目中,使用redis作为django的缓存,多一些,尽量不使用原生redis操作

 

前后端分离中,使用 cache.set   cache.get   

前后端混合中  

  可以整站缓存
  可以要缓存一个页面
  可以缓存页面中的某个位置

可以缓存的位置:

  内存中
  本地文件中
  数据库中
  reids中 (咱们用的多)

 

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等

 

celery的快速使用

开源的,小组织,不支持win,不要就win的问题展开讨论了
win上:需要借助于第三方

1、安装

  pip install celery  # 最新 5.3.4

2、写代码

先在一个文件中写

 

3、提交任务,使用别的进程

在另一个py文件中

 

4、启动worker,可以在3之前执行

 windows:
  pip3 install eventlet
  celery -A main(导入文件的名字) worker -l info -P eventlet

  执行的时候要cd到main(自己导入文件的名字)下才能执行
mac linux
  celery -A main worker -l info

 

提交任务,要启动work才能查看到结果,如果没有启动,结果就会是任务等待被执行。

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('任务已经开始被执行')

 

补充问题

from django.contrib import admin
from django.urls import path, include
from home import views  # pycharm报错,但实际上不报错 ,只需要把加入到环境变量的路径都做成source root即可
from django.views.static import serve
from django.conf import settings
import os
from django.shortcuts import HttpResponse

class Foo():
    url = 'http://www.baidu.com'

    def demo(self,request):
        # self 就不是Foo的对象了,它是request对象
        print(type(self)) # django.core.handlers.wsgi.WSGIRequest
        print(self.url) # 'WSGIRequest' object has no attribute 'url'
        return HttpResponse('sdfa')


urlpatterns = [


    path('demo/', Foo().demo),  # Foo.demo(request)
]

 

posted @ 2023-10-18 17:27  别管鱼油我了  阅读(3)  评论(0编辑  收藏  举报