1 基础知识
1.1 GC机制
Python的垃圾回收,其实高级的语言都有自己的垃圾回收机制简称GC,
python当中主要通过三种方式解决垃圾回收的方式,引用计数、标记清除、分代回收。引用计数:如果有新的引用指向对象,对象引用计数就加一,引用被销毁时,
对象引用计数减一,当用户的引用计数为0 时,该内存被释放标记清除:
首先标记对象( 垃圾检测) ,然后清除垃圾( 垃圾回收) 》首先初始所有对象标记为白色,
并确定根节点对象( 这些对象是不会被删除) ,标记它们为黑色( 表示对象有效) 。将有效对象引用的对象标记为灰色( 表示对象可达,但它们所引用的对象还没检查) ,
检查完灰色对象引用的对象后,将灰色标记为黑色。重复直到不存在灰色节点为止。
最后白色结点都是需要清除的对象分代回收: 垃圾回收器会更频繁的处理新对象。一个新的对象即是你的程序刚刚创建的,
而一个老的对象则是经过了几个时间周期之后仍然存在的对象。
Python会在当一个对象从零代移动到一代,或是从一代移动到二代的过程中提升( promote) 这个对象。
1.2 装饰器、生成器、迭代器
装饰器: 写代码要遵循开放封闭原则,装饰器本质上是一个嵌套函数( 被套着的函数就是闭包) ,
它接收被装饰的函数( func) 作为参数,并返回一个包装过的函数。在不改变被装饰函数的
代码情况下给被装饰函数或程序添加新的功能, @wrsps可以保证装饰器修饰的函数的name
的值保持不变,使装饰器更加的完美加载顺序自下而上,执行顺序自上而下应用: 当我们记录日志的时候,执行某函数、给某个功能添加日志。
闭:指的该函数是定义在函数内的函数
包:指的就是该函数引用了一个外层函数作用域的名字(e作用域的名字)
封闭:已实现的功能代码块
开放:对扩展开发
生成器: yield 关键字、那么函数名( ) 结果就是生成器、并且不会执行函数内部代码,生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器
应用:爬虫
对比return 可以返回多次值、可以挂起保存函数的运行状态
应用: redis缓存
迭代器: 不依赖索引取值、__iter__迭代器、__next__生成器,通过迭代取值的方案,可以节省内存其中迭代器又分为可迭代对象和迭代器对象,可迭代对象内置有__iter__的方法的对象都叫可迭代的对象
1.3 三元表达式、列表生成式、生成器表达式
1 三元表达式:是python为我们提供的一种简化代码的解决方案res = 条件成立时返回的值 if 条件 else 条件不成立时返回的值
2 列表生成式:就相当于把for 循环写到列表中,一行代码完成一个功能,简化代码,但是写的复杂的话会影响阅读,一般也不怎么用res = [ x for x in range ( 10 ) ] print ( res)
3 生成器表达式:将列表生成式的[ ] 换成( ) 即可,对比列表生成式返回的是一个列表,而生成器表达式返回的是一个生成器对象, 对比列表生成式,生成器表达式的优点自然是节省内存( 一次只产生一个值在内存中)
1.4 函数递归
在调用一个函数的内部又调用自己,所以递归的本质就是一个循环的过程,
它的大前提就是递归调用一定要在某一层结束,如果不结束,会形成一个死循环。
递归分为两个阶段,回溯,向下一层一层挖井,递推,向上一层一层返回
items= [ [ 1 , 2 ] , 3 , [ 4 , [ 5 , [ 6 , 7 ] ] ] ]
def func ( items) :
for x in items:
if type ( x) is list :
func( x)
else :
print ( x, end= ' ' )
func( items)
匿名函数就是没有名字的函数,临时只用一次,语法:
lambds 参数1 ,参数2 ,. . . : expression
单例模式: ( 单一职责原则) : 保证一个类仅有一个实例,并提供一个访问它的全
局访问点、比如桌面上的垃圾回收站
2 面向对象
2.1 OOP面向对象编程
面向对象编程的核心是对象二字,对象就是一个用来盛放数据与功能的容器,基于该思想
编写程序就是创造一个个的容器,其优点是扩展性强,但是它也有缺点,就是提高了编程的
复杂度。在程序中,是先定义类,后产生对象,这里的对象就是容器,是用来存放数据与
功能的,而类也是"容器" ,用在存放同类对象共有的数据与功能面向对象编程有三大特征:封装,继承,多态
1 封装:将多个属性和方法封装到一个抽象的类中、所有类的对象都可以对其调用。针对封装到对象或者类中的属性,我们还可以严格控制对他们的访问,分别是隐藏与开放接口,隐藏属性是采用用下划线开头的方式将属性隐藏起来,设置成私有的,仅仅是一种变形操作,类里定义属性就是为了使用,隐藏并不是目的,而是限制了类外部对数据的直接操作,类内应该提供相应的接口来允许类外部间接的操作数据,接口之上可以附加额外的逻辑来对数据的操作进行严格的控制2 继承:实现代码的重用、继承父类、重用父类的属性和方法、减少代码的冗余。继承描述的是子类与父类之间的关系,是一种什么是什么的关系,需要先抽象再继承。抽象:最主要的作用是划分类别(可以隔离关注点,降低复杂度)抽象即总结相似之处,总结对象之间的相似之处得到类,总结类与类之间的相似之处就可以得到父类在python2中有经典类和新式类之分,没有显式的继承object 类的类,以及该类的子类,都是经典类,显示的继承object 的类,以及该类的子类,都是新式类。但是在python3中,既是没有显示的继承object ,也会默认继承该类1 经典类:深度优先2 新式类:广度优先3 多态:多态指的是一类事物有多种形态,多态性指的是可以在不用考虑对象具体类型的情况下而直接使用对象、但是需要依赖封装和继承、在python中推崇鸭子类型:完全不依赖继承、制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象鸭子类型:是动态类型的一种风格, 不管对象属于哪个, 也不管声明的具体接口是什么, 只要对象实现了相应的方法, 函数就可以在对象上执行操作。即忽略对象的真正类型,转而关注对象有没有实现所需的方法、签名和语义. 是动态类型的一种风格, 不管对象属于哪个, 也不管声明的具体接口是什么, 只要对象实现了相应的方法, 函数就可以在对象上执行操作。即忽略对象的真正类型,转而关注对象有没有实现所需的方法、签名和语义. 多态( polymorphism) 是指同一个方法调用,由于对象不同可能会产生不同的行为。
注意:
1. 多态是方法的多态,属性没有多态
2. 多态的存在有两个必要条件:继承、方法重写( 一个类它继承了一个类,但是它又改写了它父类的方法,这样在调用这个方法时,就会因为实例对象的不同而调用的方法不同,也就是说看这个实例对象实例化时是用父类实例化的,还是子类实例化的,是父类实例化的,结果就是父类的方法,是子类实例化的,结果就是子类的方法)
2.1 继承原理 MRO方法
菱形问题:如果A中有一个方法,B和/ 或C都重写了该方法,而D没有重写它,那么D继承的是哪个版本的方法:B的还是C的?对于你定义的每一个类,python都会计算出一个方法解析顺序( MRO) 列表,该MRO列表就是
一个简单的所有基类的线性顺序列表,python会在MRO列表上从左往右一次开始查找基类,
直到找到第一个匹配这个属性的类为止。MRO列表会遵循如下三条准则
1 、子类会先于父类被检查
2 、多个父类会根据它们在列表中的顺序被检查
3 、如果对下一个类存在两个合法的选择,选择第一个父类super ( ) 获得父类定义。在子类中,如果想要获得父类的方法时,我们可以通过super ( ) 来做,super ( ) 代表父类的定义,而不是父类对象。
2.2 绑定方法和非绑定方法
但凡在类中定义一个函数,默认就是绑定给对象的,应该由对象来调用,
会将对象当作第一个参数自动传入classmethods:绑定给类的方法,由类来调用,自动将类本身当作第一个参数传入
staticmethod :非绑定方法,不与类和对象绑定,类和对象都可以调用,普通函数,没有自动传值
property :一种特殊属性、访问它时会执行一段功能,用来绑定给对象的方法,将函数对象伪装成数据属性,然后返回值
应用:django模型类中写子序列化的方法,跨表操作
2.3 反射、CBV源码简述
python中的反射就是通过字符串的形式操作对象相关的属性,python中一切事物都是对象,都可以用到反射。** 反射机制:** 指的是在程序的运行状态中对于任意一个类,都可以知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意方法和属性。
这种动态获取程序信息以及动态调用对象的功能称为反射机制。
hasattr 检测是否含有某属性
getattr 获取属性
setattr 设置属性
delattr 删除属性好处: 反射可以提前定义好接口、接基于类的视图应用场景:
CBV源码简述:根据前端请求方式的不同自动匹配执行对应的方法:在url路由中的views. 类 名. as_view( ) 的源码下可以看到是被@classonlymethod修饰的类方法,内部定义闭包函数传参并返回闭包函数名、在dajong启动的时候会执行urls的as_view( ) 产生变 形为views. view,在浏览器提交请求的时候就会触发view方法,通过view下的self 使用类的对象,返回self. dispatch属性、在父类中的dispathc函数通过反射机制就 通过字符串操作对象属性口只有在被完成后才会真正执行,就是可以事先写好逻辑接口,事后实现接口功能
2.4 元类、魔法方法、猴子补丁
元类:创建类的类就叫元类(metaclass)函数type 其实就是一个元类,
type 就是Python在背后用来创建所有类的元类。魔法方法: __call__, __init__, __new__,__str__. . . 类加( ) 触发类的元类的__call__方法
__str__ 打印时触发 str 函数或者print 函数—> obj. str ( )
__init__ 是初始化方法,通过类创建对象时,自动触发执行
__new__ 是创建对象时为对象分配空间、在初始化init之前被调用当我们创建实例的时候: __new__方法在__init__方法之前被调用并将__new__方法的
返回值将传递给__init__方法作为第一个参数,最后__init__给这个实例设置一些参数。猴子补丁: 猴子补丁得益于python灵活的语法,一切皆对象的思想。
猴子补丁的主要功能就是动态的属性的替换。虽然属性的运行时替换和猴子也没有什么关系,所以说猴子补丁的叫法有些莫名其妙,但是只要"模块运行时替换的功能" 对应就行了。
猴子补丁允许运行期间动态修改一个类或模块
3 常用模块
os模块式与操作系统交互的一个接口
os. path. join( path1[ , path2[ , . . . ] ] ) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os. path. splitext( ) 将文件名和扩展名分开
os. path. split( ) 返回文件的路径和文件名
os. mkdir( 'dirname' ) 生成单级目录;相当于shell中mkdir dirname
os. remove( ) 删除一个文件
sys
sys. path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys. exit( n) 退出程序,正常退出时exit( 0 )
sys. version 获取Python解释程序的版本信息
re
正则
\w 匹配数字字母下划线
\W 匹配非字母数字下划线
^ 匹配字符串的开头
$ 匹配字符串的末尾
random
生成随机数
print ( random. random( ) )
print ( random. randint( 1 , 3 ) )
logging
记录日志
日志级别有五种
logging. debug( '调试debug' )
logging. info( '消息info' )
logging. warning( '警告warn' )
logging. error( '错误error' )
logging. critical( '严重critical' )
json& pickle
json是可以在不同语言之间交换数据的,而pickle只在python之间使用
json只能序列化最基本的数据类型,而pickle可以序列化所有的数据类型,包括类,函数都可以序列化
4 进程线程协程
进程是CPU资源分配的基本单位,线程是独立运行和独立调度的基本单位(CPU上真正运行的是线程)。
进程拥有自己的资源空间,一个进程包含若干个线程,线程与CPU资源分配无关,多个线程共享同一进程内的资源。
线程的调度与切换比进程快很多。
协程是单线程下的并发,是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
对于多核CPU,利用多进程+ 协程的方式,能充分利用CPU,获得极高的性能
"""
Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它
是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调
度。
"""
5 异步和同步
我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务同步:提交一个任务,提交之后在原地等待提交的结果,之后再去提交下一个任务。某功能调用时,在没有得到结果之前,该调用就不会返回
异步:提交一个任务,提交之后不等提交的任务运行完直接提交下一个任务。异步的概念和同步相对。同步与异步针对的是函数/ 任务的调用方式:同步就是当一个进程发起一个函数(任务)调用的时候,一直等到函数(任务)完成,而进程继续处于激活状态。而异步情况下是当一个进程发起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行当,函数返回的时候通过状态、通知、事件等方式通知进程任务完成。
6 GIL锁/互斥锁
1 、首先明确GIL并不是Python的特性,它是在实现Python解析器( CPython) 时所引入的一个概念
2 、GIL:全局解释器锁。每个线程在执行的过程都需要先获取GIL,保证同一时刻只有一个线程可以执行代码。
3 、当前线程遇到I/ O,或者字节码执行100 行(使用计时器时间到达阈值释放GIL),才会释放GIL锁。线程的运行仍然是有先后顺序的,并不是同时进行。
4 、Python使用多进程是可以利用多核的CPU资源的。
5 、多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁。 多进程可以充分使用cpu的两个内核而多线程却不能充分使用cpu的两个内核cpython解释器中存在一个GIL( 全局解释器锁) ,它的作用就是保证同一时刻只有一个线程可以执行代码,因此造成了我们使用多线程的时候无法实现并行。解决方案:
1 )更换解释器比如使用jpython(java实现的python解释器)(jpython xxx. py)
2 )使用其他语言(C语言)编写程序
3 )使用多进程完成多任务的处理
"""
多个进程操作同一份数据的时候,会出现数据错乱的问题
针对上述问题,解决方法就是加锁处理,将并发变成串行,牺牲效率但是保证了数据的安全扩展:
行锁 表锁注意:
1、锁不要轻易的使用,容易造成死锁现象(我们一般写代码不会用到,都是内部封装好的)
2、锁只在处理数据的部分加起来保证数据安全(只在争抢数据的环节加锁处理即可)
"""
7 HTTP/HTTPS协议
1 、什么是HTTP? 数据传输是明文超文本传输协议是一个基于请求响应,无状态的,作用于tcp/ ip应用层的协议之上的协议,它规定了浏览器与服务端之间数据交互的格式,设计HTTP的初衷是为了提供一种发布和接收HTML页面的方法。绝大多数的Web开发,都是构建在HTTP协议之上的Web应用。2 、什么是HTTPS? 数据传输是密文安全超文本传输协议HTTPS是一种通过计算机网络进行安全通信的传输协议。HTTPS使用的主要目的是提供对网站服务器的身份认证,同时保护交换数据的隐私与完整性。3 、HTTP vs HTTS
HTTP特点:
( 1 ) 无状态:协议对客户端没有状态存储,对事物处理没有“记忆”能力,比如访问一个网站需要反复进行登录操作
( 2 ) 无连接:HTTP/ 1.1 之前,由于无状态特点,每次请求需要通过TCP三次握手四次挥手,和服务器重新建立连接。比如某个客户机在短时间多次请求同一个资源,服务器并不能区别是否已经响应过用户的请求,所以每次需要重新响应请求,需要耗费不必要的时间和流量。
( 3 ) 基于请求和响应:基本的特性,由客户端发起请求,服务端响应
( 4 ) 简单快速、灵活
( 5 ) 通信使用明文、请求和响应不会对通信方进行确认、无法保护数据的完整性HTTPS特点:
( 1 ) 基于HTTP协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护
( 2 ) 内容加密:采用混合加密技术,中间者无法直接查看明文内容
( 3 ) 验证身份:通过证书认证客户端访问的是自己的服务器
( 4 ) 保护数据完整性:防止传输的内容被中间人冒充或者篡改websocket协议 数据传输是密文
数据格式
"""
请求数据格式
请求首行(请求方法...)
请求头(一大堆K:V键值对)
请求体(并不是所有的请求方法都有 主要用来携带敏感性数据)
响应数据格式
响应首行(响应状态码...)
响应头(一大堆K:V键值对)
响应体(展示给用户的数据)
"""
8 tcp/udp协议
1 tcp协议:可靠传输,TCP数据包没有长度限制,理论上可以无限长,但是为了保证网络的效率,通常TCP数据包的长度不会超过IP数据包的长度,以确保单个TCP数据包不必再分割。
2 udp协议:不可靠传输,”报头”部分一共只有8 个字节,总长度不超过65 , 535 字节,正好放进一个IP数据包。1 为什么连接的时候是三次握手,关闭的时候却是四次握手?因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了" 。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
"""
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
"""
9 django
9.1 MTV
Django 是一个由 Python 编写的一个开放源代码的 Web 应用框架。
是基于MTV模式的框架,需要配合url控制器(路径分发)使用!Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是指:
· M 代表模型(Model): 负责业务对象和数据库的关系映射( ORM) 。
· T 代表模板 ( Template) :负责如何把页面展示给用户( html) 。
· V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给
不同的View处理,View再调用相应的Model和Template优势:低耦合,开发快捷,部署方便,可重用性高,维护成本低。
Python + Django 是快速开发、设计、部署网站的最佳组合
9.2 ORM
orm:对象关系映射
orm目的就是为了能够让不懂SQL 语句的人通过python面向对象的知识点也能够轻松自如的操作数据库
类
对象
对象点属性
缺陷:sql 封装死了 有时候查询速度很慢
9.3 forms组件
能够完成的信息
1 、渲染html代码,2 、校验数据,3 、展示提示信息** * 为什么数据校验非要去后端不能在前端利用js直接完成呢?** *
数据校验前端可有可无,但是后端必须要有!!!
因为前端的校验是弱不禁风的 你可以直接修改,或者利用爬虫程序绕过前端页面直接朝后端提交数据钩子函数
"""
钩子函数在form组件中能够让我们自定义校验规则
在froms组件中有两类钩子
1、局部钩子:'单'个字段增加校验规则
2、全局钩子:给'多'个字段增加校验规则
"""
9.4 auth模块
Auth 模块是Django 自带的用户认证模块:我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统。此时我们需要实现包括用户注册、用户登录、用户认证、注销、修改密码等功能,所以说比较麻烦。Django 作为一个完美主义者的终极框架,它内置了强大的用户认证系统–auth ,它默认使用 auth_user 表来存储用户数据。auth 模块的常用方法: authenticate ( ) 提供了用户认证功能,即验证用户名以及密码是否正确,一般需要username 、password 两个关键字参数, 如果认证成功(用户名和密码正确有效),便会返回一个 User 对象login ( HttpRequest , user ) 该函数接受一HttpRequest 对象,以及一个经过认证的User 对象。该函数实现一个用户登录的功能。它本质上会在后端为该用户生成相关session 数据。logout ( request ) * 该函数接受一个HttpRequest 对象,无返回值。当调用该函数时,当前请求的session 信息会全部清除。该用户即使没有登录,使用该函数也不会报错is_authenticated ( ) 用来判断当前请求是否通过了认证。
9.5 DTL语法
模板语言:主要用于前后端混合开发的项目,后端为前端页面传值的语法模版语法之变量在 Django 模板中遍历复杂数据结构的关键是句点字符, 语法:{{变量名}}模板语言之标签标签看起来像是这样的: { % tag % } 标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签( 例如{ % tag % } . . . 标签内容 . . . { % endtag % } )
9.6 F、Q查询
F作用:两个字段之间作比较,专门取对象中某列值的操作
F对象允许Django在未实际链接数据的情况下具有对数据库字段的值的引用。在更新数据时需要先从数据库里将原数据取出后放在内存里,然后编辑某些属性,最后提交。查询男生比女生多的公司
models. company. filter ( c_boy_num__gt= F( 'c_girl_num' ) ) Q作用:对对象进行复杂查询,并支持& (and ), | (or ),~ (not )操作符(与或非)运算来组合生成不同的Q对象,便于在查询操作中灵活地运用。如果Q查询和关键字查询同时存在时,Q查询要放在关键字查询的前面!查询名字不是红楼梦的书:
models. Book. objects. filter ( ~ Q( name= '红楼梦' ) )
9.7 中间件
中间件是一个用来处理Django的请求和响应的框架级别的钩子。
它是一个轻量、低级别的插件系统,用于在全局范围内
改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是
一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。
但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware' ,
'django.contrib.sessions.middleware.SessionMiddleware' ,
'django.middleware.common.CommonMiddleware' ,
'django.middleware.csrf.CsrfViewMiddleware' ,
'django.contrib.auth.middleware.AuthenticationMiddleware' ,
'django.contrib.messages.middleware.MessageMiddleware' ,
'django.middleware.clickjacking.XFrameOptionsMiddleware' ,
]
MIDDLEWARE配置项是一个列表( 列表是有序的) ,列表中是一个个字符串,这些字符串其实
是一个个类,也就是一个个中间件。Django默认有七个中间件,但是django暴露给用户可以自定义中间件并且里面可以写五种方法
1 、process_request : 请求进来时, 权限认证 。
2 、process_view : 路由匹配之后, 能够得到视图函数
3 、process_exception : 异常时执行
4 、process_template_responseprocess : 模板渲染时执行
5 、process_response : 请求有响应时执行process_request方法
1. 请求来的时候需要经过每一个中间件里面的 process_request方法,经过的顺序是按照配置文件中注册的中间件从上往下的顺序依次执行
2. 如果中间件里面没有定义该方法,那么直接跳过执行下一个中间件
3. 它的返回值可以是None ,按正常流程继续走,交给下一个中间件处理,如果该方法返回了Httpresponse对象,那么请求将不再继续往后执行,而是直接原路返回(校验失败不允许访问. )process_request方法就是用来做全局相关的所有限制功能process_response方法
1. 响应走的时候需要经过每一个中间件里面的 process_response方法,该方法有两个额外的参数 request, response
2 , 该方法必须返回一个 HttpResponse对象: 默认返回的就是形参 response, 你也可以自己返回自己的
3. 顺序是按照配置文件中注册了的中间件从下往上依次经过,如果你没有定义的话直接跳过执行下一个总结:当前端发来请求,Django会执行每个中间件中的process_request, 执行顺序按照
配置文件由上至下执行。响应走的时候,Django会执行每个中间件中的process_response 方法,process_response方法是在视图函数之后执行的,执行顺序是按照配置文件中
注册了的中间件从下往上依次执行
9.8 路由分发
当一个url请求过来之后,先到项目主目录下的urls内。
然后由这个url做处理分发给其他app内的urls一级路由:主目录urls内引入include
二级路由:只查找本地urls内的路径
自动生成路由: SimpleRouter、DefaultRouterViewSetMixin+ 9 个子类视图才能自动生成路由** * Default与Simple的区别是: ** *
Default会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。
from rest_framework. routers import SimpleRouter, DefaultRouter
router = SimpleRouter( )
router. register( 'books' , views. BookView)
10 DRF
10.1 Restful 规范
RESTful 是一种定义Web API 接口的设计风格,尤其适用于前后端分离的应用模式中。数据的安全保障:url 链接一般都采用https 协议进行传输( 数据交互中安全性) 接口特性表现:一看就知道是个api 接口,用api 关键字标识接口url :https :// api . baidu . com 多数据版本共存:在url 链接中标识数据版本https :// api . baidu . com / v1 数据即是资源,
均使用名词(可复数),尽量不要出现动词资源操作由请求方式决定(method ):
提供请求方式来标识增删改查动作过滤,通过在url 上传参的形式传递搜索条件:
例如url 后面?= 搜索,分页,游标
10.2 jwt认证
JWT(JSON Web Token)
JWT 就是一种在用户登录后生成token 并把token 放在前端,后端不需要维护用户的
状态信息但是可以验证token 有效性的认证及状态管理方式。JWT的构成(base64的使用:加码和解码)
1. 头部(Header)存放如何处理token的方式:加密的算法、是否有签名等
2. 载荷(Payload)数据的主体部分:用户信息、发行者、过期时间等
3. 签名(Signature)将header、payload再结合密码盐整体处理一下最后一步签名的过程,实际上是对头部以及负载内容进行签名,防止内容被篡改。如果有人
对头部以及负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成新的
JWT的话,那么服务器端会判断出新的头部和负载形式的签名和JWT附带上的签名是不一样
的。如果要对新的头部和负载进行签名,在不知道服务器加密时用的密钥的话,
得出来的签名也是不一样的。
11 View家族
两个基类
APIView 是RESTframework 提供的所有视图的基类,继承自Django 的View 父类
GenericAPIView [ 通用视图类] 继承自APIVIew ,主要增加了操作序列化器和数据库查询
方法,作用是为下面Mixin 扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin 扩展类。# 5 个视图扩展类( rest_framework . mixins )
CreateModelMixin :create 方法创建一条
DestroyModelMixin :destory 方法删除一条
ListModelMixin :list 方法获取所有
RetrieveModelMixin :retrieve 获取一条
UpdateModelMixin :update 修改一条# 9 个子类视图( rest_framework . generics )
CreateAPIView : 继承CreateModelMixin , GenericAPIView ,有post 方法,新增数据
DestroyAPIView :继承DestroyModelMixin , GenericAPIView ,有delete 方法,删除数据
ListAPIView :继承ListModelMixin , GenericAPIView , 有get 方法获取所有
UpdateAPIView :继承UpdateModelMixin , GenericAPIView ,有put 和patch 方法,修改数据
RetrieveAPIView :继承RetrieveModelMixin , GenericAPIView ,有get 方法,获取一条
ListCreateAPIView :有get 获取所有,post 方法新增
RetrieveDestroyAPIView :有get 方法获取一条,delete 方法删除
RetrieveUpdateAPIView :有get 获取一条,put ,patch 修改
RetrieveUpdateDestroyAPIView :有get 获取一条,put ,patch 修改,delete 删除# 视图集
ViewSetMixin :重写了as_view
ViewSet :继承ViewSetMixin 和APIView
GenericViewSet :继承ViewSetMixin , generics . GenericAPIView
ModelViewSet :继承了GenericViewSet 和五个视图扩展类,5 个接口都有
ReadOnlyModelViewSet :继承mixins . RetrieveModelMixin , mixins . ListModelMixin , GenericViewSet action 装饰器:
自动生成路由后,使用action 装饰器来继续让写在视图类的方法,可以被访问到
11.1 序列化器、局部,全局钩子
前后端不分离项目:有form组件帮我们去做数据校验,有模板语法,从数据库取出queryset对象不需要人为去转格式前后端分离项目:
我们需要自己去做数据校验, 手动去转数据格式,因为跨平台数据传输都用json字符串,不能直接jsonqueryset对象
1 序列化:把python中的对象转成json格式字符串,序列化器会把模型对象转换成字典, 经过response以后变成json字符串
2 反序列化:把json格式字符串转成python中的对象,把客户端发送过来的数据, 经过request以后变成字典
source:指定要序列化的字段,只有一个字段(也可以跨表)
SerializerMethodField:跨表查(( 来定制返回的字段) 要么是列表,要么是字典)序列化器
- 定义一个类,继承Serializer
- 在类内些字段(常用字段,和非常用字段)(字段参数)
- 在视图类中,实例化得到一个序列化类的对象,传入要序列化的数据
- 对象. data- - - 》就是字典serializer不是只能为数据库模型类定义,也可以为非数据库模型类的数据定义。
serializer是独立于数据库之外的存在。如果我们想要使用序列化器对应的是Django的
模型类,DRF为我们提供了ModelSerializer模型类序列化器来帮助我们快速创建一个
Serializer类局部钩子,全局钩子函数单个字段校验,validate_字段名在序列化器中
需要同时对多个字段进行比较验证时,可以定义validate方法来验证
11.2 rbac模式
RBAC 是基于角色的访问控制( Role- Based Access Control)
在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。
这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。应用: Django的 Auth组件 采用的认证规则就是RBAC
1 )像专门做人员权限管理的系统(CRM系统)都是公司内部使用,所以数据量都在10w以下,一般效率要求也不是很高
2 )用户量极大的常规项目,会分两种用户:前台用户( 三大认证) 和 后台用户( BRAC来管理) 结论:没有特殊要求的Django项目可以直接采用Auth组件的权限六表,
不需要自定义六个表,也不需要断开表关系,单可能需要自定义User表
11.3 分页
原生django有分页功能,也可以自定义封装分页继承Paginator类drf,三种分页功能
1 基本分页:PageNumberPaginationpage_size = 2 page_query_param = 'page' max_page_size = 4 page_size_query_param = 'size' page= 3 & size= 3 2 偏移分页:LimitOffsetPaginationdefault_limit= 2 limit_query_param= 'limit' offset_query_param = 'offset' max_limit = 5 3 游标分页:CursorPaginationcursor_query_param = 'cursor' page_size = 2 ordering = 'id' pagination_class = CustomNumberPagination
11.4 过滤、排序
过滤:
1 过滤针对于 list 获取所有(对于列表数据可能需要根据字段进行过滤)
2 在请求路径中带过滤条件,对查询结果进行过滤
filter_backends = [ SearchFilter, ]
search_fields = [ 'name' ,'price' ] 第三方过滤类使用(django- filter )
内置的SearchFilter过滤类,功能一般,如果想实现更高级的过滤,
可以使用第三方通过添加django- fitlter扩展来增强支持,自己定义过滤类,支持模糊查询排序:在类视图中设置filter_backends(排序本身也是过滤)
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。使用rest_framework. filters. OrderingFilter过滤器,
REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,
如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。
11.5 异常处理、自动生成接口文档
我们在生产环境中,需要把全部异常捕获,输入到日志中。而且我们也不希望给错误页面给用户看到,这时候应该怎么办呢?
这时候可以针对 DRF 框架没有处理的一些特殊的异常,进行全局的异常处理。drf 提供了异常处理,我们可以自定义异常处理函数。
需要在配置文件中声明自定义的异常处理,如果未声明,会采用默认的方式。DRF 可以自动帮助我们生成接口文档。接口文档以网页的方式呈现。
自动接口文档能生成的是继承自APIView及其子类的视图。生成接口文档需要coreapi库的支持。在总路由中添加接口文档路径。文档路由对应的视图配置为:rest_framework. documentation. include_docs_urls,
参数title为接口文档网站的标题。
from rest_framework. documentation import include_docs_urls
urlpatterns = [ url( r'^docs/' , include_docs_urls( title= 'My REST API' ) )
]
12 数据库
12.1 索引、索引下推技术
索引:是一种数据结构(既结构数据),换句话说:索引就是一种组织数据的方式
hash 索引:是基于hash 表实现,记算出hash 值对应的k value 适合等值查询,不适合范围查询* * * 树索引:* * *
1 二叉树:非叶子节点只允许最多两个子节点存在,右边的子节点大于当前节点的值,每个节点只存储一个键值和数据
2 平衡二叉树:左右高度子节点不超过1 、在数据量大的时候会进行多次磁盘io,降低查找效率
3 B树(平衡树):每个节点储存更多的键值key 和数据data ,并且每个节点拥有更多的子节点。
4 B+ 树:在非叶子节点上,不保存数据,只存放键值,能存储更多的键值,所有数据均存储在叶子节点,并且是按照顺序排列的。查找数据会减少IO,数据查询的效率更快。这使得B+ 树在做范围查找、分段查找、去重查找、分组查找异常简单。* * * 为什么索引结构默认使用B+ 树,而不是Hash ,二叉树,红黑树?* * *
1 Hash :虽然可以快速定位,但是没有顺序,IO复杂度高。
2 二叉树:树的高度不均匀,不能自平衡,查找效率跟树的高度有关,并且IO代价高。
3 红黑树:树的高度随着数据量增加而增加,IO代价高。1 普通索引 一张表中可以有多个普通索引,随便一个字段都可以建立的索引,我们平常建立的索引大部分都是普通索引
2 联合索引 好几个字段联合起来建立的索引
3 唯一索引 业务中唯一的字段适合建立唯一索引,一个表中可以有多个唯一索引
4 主键索引 和唯一索引一样,主键索引也是唯一的,不同的就是,一个表只能有一个主键索引* * * 索引下推技术:* * * 索引下推(index condition pushdown )简称ICP。
在"不使用ICP" 的情况下,在使用非主键索引(又叫普通索引或者二级索引)进行查询时,存储引擎通过索引检索到数据,然后返回给MySQL服务器,服务器然后判断数据是否符合条件。
在"使用ICP" 的情况下,如果存在某些被索引的列的判断条件时,MySQL服务器将这一部分判断条件传递给存储引擎,然后由存储引擎通过判断索引是否符合 MySQL服务器传递的条件,只有当索引符合条件时才会将数据检索出来返回给MySQL服务器。
"索引条件下推" 优化可以减少存储引擎查询基础表的次数,也可以减少MySQL 服务器从存储引擎接收数据的次数。
12.2 explain、事务
explain :索引执行计划查看rows 的大小, rows 是核心指标、优化语句主要在优化rows 事务(ACID):
数据库事务指的则是作为单个逻辑工作单元执行的一系列操作(SQL 语句) 功能:
1 为数据库操作提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
2 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。这些操作要么全部执行,要么全部不执行。* * * 事务的四大特性?* * *
1 原子性 Atomicity:事务作为一个整体,包含在其中对于数据库的操作,要么全部执行,要么全部不执行。例如:A给B转了100 ,A余额减100 ,刚转完系统崩溃,B收到钱款这一操作没有执行,则整个事务回滚,100 元退还到A的余额
2 一致性 Consistency:事务应该确保数据库从一致状态转到另一个一致状态。例如:转账行为中,一个人减了50 元,另外一个人就应该加上这50 元,而不能是40 元。其他一致状态的含义是数据库中的数据应满足完整性约束,例如字段约束不能为负数,事务执行完毕后的该字段也同样不是负数。
3 隔离性 Isolation :多个事务并发执行时,一个事务的执行应该不受其他事务执行的影响。举例:A给B转100 元和C给B转100 元是独立的。
4 持久性 Durability:成功执行的事务产生的结果应该被永久保留在数据库中。
12.3 触发器、存储过程、视图
1 触发器:触发器是一个特殊的存储过程,它是MySQL在insert 、update 、delete 的时候自动执行的代码块。
2 视图:视图是由查询结果形成的一张虚拟表,是表通过某种运算得到的一个投影create view view_name as select 语句
3 存储过程:把一段代码封装起来,当要执行这一段代码的时候,可以通过调用该存储过程来实现( 经过第一次编译后再次调用不需要再次编译,比一个个执行sql 语句效率高) create procedure 存储过程名( 参数, 参数, …)
12.4 常见约束
约束含义:一种限制,用于限制表中的数据,为了保证表中数据的准确性和可靠性。分类:六大约束
1. NOT NULL :非空,用于保证该字段的值不能为空。例如学生表的学生姓名及学号等等。
2. DEFAULT :默认值,用于保证该字段有默认值。例如学生表的学生性别
3. PRIMARY KEY :主键,用于保证该字段的值具有唯一性并且非空。例如学生表的学生学号等。
4. UNIQUE :唯一,用于保证该字段的值具有唯一性,可以为空。例如注册用户的手机号,身份证号等。
5. CHECK :检查约束(MySql不支持),检查字段的值是否为指定的值。
6. FOREIGN KEY :外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值,在从表添加外键约束,用于引用主表中某些的值。例如学生表的专业编号添加约束的实际:
1. 创建表时
2. 修改表时约束的添加分类:
1 列级约束:六大约束语法上都支持,但外键约束没有效果
2 表级约束:除了非空、默认、其它的都支持。
12.5 SQL语句、SQL注入
SQL 语言主要用于存取数据、查询数据、更新数据和管理关系数据库系统, SQL 语言由IBM开发。SQL 语言分为3 种类型:
1 DDL语句 数据库定义语言: 数据库、表、视图、索引、存储过程,例如CREATE DROP ALTER
2 DML语句 数据库操纵语言: 插入数据INSERT 、删除数据DELETE 、更新数据UPDATE 、查询数据SELECT
3 DCL语句 数据库控制语言: 例如控制用户的访问权限GRANT 、REVOKE sql 注入: 利用现有的程序,将恶意的sql 命令注入到后台的数据库引擎执行的能力。像符号( 两横杠'--' ) 会注释掉之后的sql ,根本原理就是字符串的拼接name= '%s' 原生sql 中让execute 帮做拼接就可以,django的orm种就不会存在这个问题
12.6 MVCC、事务隔离级别、读现象
多版本控制mvcc:
保证隔离性多版本并发控制,保存数据在某个节点的快照,读不加锁,读写不冲突,增加并发创建时间的版本号,过期时间的版本号,开启新事务、版本号都会递增事务的隔离级别: 未提交读、提交读、可重复读、可序列化'锁'
1 Read uncommitted ( 读未提交) :在这种事务隔离级别下,一个事务可以读到另外一个事务未提交的数据。可能会脏读
2 Read committed ( 读已提交) :在一个事务修改数据过程中,如果事务还没提交,其他事务不能读该数据。可能会出现不可重复读
3 Repeatable read ( 可重复读) :由于读已提交隔离级别会产生不可重复读的读现象。所以,比读已提交更高一个级别的隔离级别就可以解决不可重复读的问题。这种隔离级别就叫可重复读
4 Serializable ( 可序列化) :是最高的隔离级别,前面提到的所有的隔离级别都无法解决的幻读,在可序列化的隔离级别中可以解决。innoDB 存储引擎默认隔离级别为可重复读(Repeatable Read ),该隔离级别下,
避免了脏读、不可重复读现象的产生,对于索引的查询采用 next - key locks。
这样做就避免了幻读现象( 读已提交未提交读) , ( 读已提交) 。* * 读现象': 脏读、不可重复读、幻读* *
1 脏读:A事务读取了已经被B事务更新但是还没有提交的字段之后,若此时B回滚,A读取的内容就是无效的了,称之为脏数据;
2 不可重复读:事务A按一定条件搜索,期间事务B删除了符合条件的某一条数据,导致A 再次读取时数据少了一条。这种情况归为不可重复读;
3 幻读:事务A 按照一定条件进行数据读取,期间事务B插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取时,发现了事务B新插入的数据 称为幻读;前提:数据库的并发场景有三种
1 读- 读:不存在任何问题、不需要并发控制
2 读- 写:有隔离性问题,可能遇到脏读、幻读、不可重复读
3 写- 写:可能存在更新丢失的问题
12.7 锁机制
首先对mysql锁进行划分:
按照锁的粒度划分:行锁、表锁、页锁
按照锁的使用方式划分:共享锁、排它锁(悲观锁的一种实现)
还有两种思想上的锁:悲观锁、乐观锁。InnoDB 中有几种行级锁类型(三种算法):Record Lock 、Gap Lock 、Next - key Lock
1 Record Lock :在索引记录上加锁
2 Gap Lock :间隙锁
3 Next - key Lock :Record Lock + Gap Lock * * 行锁:* * 只针对当前操作的行加锁。行级锁能减少数据库操作的冲突。加锁粒度最小,但加锁的开销也最大。有可能会出现死锁的情况。行级锁按照使用方式分为共享锁和排他锁。
* * 表锁:* * 只针对当前的操作对整张表加锁,资源开销比行锁少,不会出现死锁的情况,但是发生锁冲突的概率很大。被大部分的mysql引擎支持,MyISAM和InnoDB 都支持表级锁,但是InnoDB 默认的是行级锁。是mysql锁中粒度最大的一种锁,
* * 页锁:* * 页级锁是MySQL中锁定粒度介于行级和表级中间的一种锁。表级锁速度快冲突多,行级冲突少速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。BDB ( 键值对数据库系统) 支持页级锁。无论是悲观锁还是乐观锁,他们本质上不是数据库中具体的锁概念,而是我们定义出来,用来描述两种类别的锁的思想。乐观锁和悲观锁的概念不仅仅存在于数据库领域,可以说存在线程安全,存在并发的场景几乎都有乐观锁和悲观锁的适用场景。悲观锁和乐观锁是一种思想也叫悲观并发控制和乐观并发控制,还有MVCC多版本并发控制
悲观锁PCC:见名知意,悲观的认为你会修改数据,所以在我修改前就加锁,再进行修改
乐观锁OCC:1 假设数据不会冲突,在数据提交的时候才会进行冲突检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。2 相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。
DBD介绍
BDB 是 Berkeley DB(Berkeley Database )的缩写,是一种嵌入式数据库管理系统
(Embedded Database Management System,简称 EDBMS)。
Berkeley DB 是由 Oracle 公司开发的一种高性能、轻量级、事务处理的键值对数据库系统。以下是 Berkeley DB(BDB )的一些主要特点和用途:
1. * * 嵌入式数据库:* * - Berkeley DB 是一种嵌入式数据库,它的数据库引擎被直接嵌入到应用程序中,而不是作为独立的服务器运行。这样可以方便地在应用程序内部管理数据。2. * * 键值对存储:* * - Berkeley DB 使用简单的键值对(key - value )存储模型。- 每个数据项都由唯一的键标识,应用程序可以通过键快速检索数据。3. * * 事务支持:* * - Berkeley DB 提供了事务支持,允许应用程序在一组操作中定义一个原子的、一致的、持久的工作单元。这确保了数据的一致性和可靠性。4. * * 高性能:* * - Berkeley DB 被设计为高性能的数据库引擎。它在处理大量并发读写操作时表现良好,适用于需要快速响应时间的应用场景。5. * * 多种存储引擎:* * - Berkeley DB 提供了多种存储引擎,包括 Btree 、Hash 、Queue 等,以满足不同类型的应用需求。6. * * 支持 ACID 特性:* * - Berkeley DB 遵循 ACID(原子性、一致性、隔离性、持久性)特性,确保数据库的可靠性和稳定性。7. * * 跨平台:* * - Berkeley DB 提供了跨平台的支持,可以在多种操作系统上运行,包括 Linux、Windows、macOS 等。8. * * 广泛应用:* * - Berkeley DB 在许多领域被广泛应用,包括嵌入式系统、网络应用、金融领域等。- 它被用于存储配置数据、缓存、日志文件等。Berkeley DB 提供了 C 语言的 API,同时也有其他语言的绑定,如 Java、Python 等。
在一些应用场景中,Berkeley DB 被认为是一种可靠的、高性能的数据库解决方案。
然而,需要注意的是,近年来 Berkeley DB 的维护和更新逐渐减少,
而且 Oracle 公司已经停止了对开源版本的维护,推荐使用其它替代数据库系统。
MVCC介绍
MVCC(Multi- Version Concurrency Control)是一种数据库管理系统(DBMS)中
用于处理并发访问的技术。它允许多个事务同时对数据库进行读写操作,而不会相互干扰,从而提高数据库的并发性能。MVCC 的核心思想是为每个事务创建一个数据版本,并在事务之间共存,而不是阻塞其他事务。
每个事务在读取数据时看到的是一个特定版本的数据,而不受其他并发事务的影响。
这有助于确保事务之间的隔离性,同时提高了系统的并发性能。MVCC 的主要组成部分包括以下几个概念:
1. * * 数据版本:* * - 在 MVCC 中,每个数据行都可以有多个版本,每个版本与一个特定的事务相关联。- 每当对数据行进行修改时,都会创建一个新的版本,并将该版本关联到执行修改的事务。2. * * 事务的可见性:* * - 事务只能看到在它开始之前已经存在的版本。- 当事务开始时,系统记录一个时间戳(或序列号),事务只能看到该时间戳之前已经存在的版本。3. * * 并发控制:* * - 当多个事务同时访问相同的数据时,MVCC 使用时间戳或其他方式来确定哪个版本的数据是对事务可见的。- 这种方式避免了读写之间的冲突,并允许多个事务同时读取相同的数据行。4. * * 回滚段:* * - 数据库通常会使用回滚段来存储已提交事务的历史版本。- 这样,即使事务已提交,其他事务仍然可以查看之前的版本。MVCC 的优势包括:
- * * 高并发性:* * 允许多个事务同时读取和修改数据,提高了数据库的并发性能。- * * 提高隔离性:* * 每个事务看到的是一个特定版本的数据,而不受其他事务的影响,提高了事务之间的隔离性。- * * 支持长事务:* * MVCC 支持长事务而不会导致锁的争用,因为每个事务操作的是自己的数据版本。MVCC 在一些主流的数据库系统中得到了广泛的应用,例如 PostgreSQL、Oracle、
MySQL 的 InnoDB 存储引擎等。这种并发控制的方法对于大规模的高并发数据库系统非常有用。
12.8 异步IO和协程的实现
在 Python 中,异步 I/ O 和协程是通过 `asyncio` 模块来实现的。
`asyncio` 提供了对异步编程的支持,其中的关键概念包括异步 I/ O 操作、协程和事件循环。以下是异步 I/ O 和协程的基本概念和实现方式:
1. ** 异步 I/ O:** - 异步 I/ O 是指在进行 I/ O 操作时,可以在等待结果的同时执行其他任务,而不会阻塞整个程序。- 在 Python 中,异步 I/ O 是通过使用 `asyncio` 提供的异步 I/ O 操作来实现的。import asyncioasync def main ( ) : result = await asyncio. sleep( 1 ) print ( "Async I/O operation completed" ) asyncio. run( main( ) ) 2. ** 协程:** - 协程是一种轻量级的线程,可以在执行期间暂停和恢复。- 在 Python 中,协程通过 `async def ` 关键字定义,并使用 `await ` 关键字进行挂起和恢复。import asyncioasync def coroutine_example ( ) : print ( "Start coroutine" ) await asyncio. sleep( 2 ) print ( "Coroutine resumed after sleep" ) asyncio. run( coroutine_example( ) ) 3. ** 事件循环:** - 事件循环是异步编程的核心,负责调度和执行异步任务。- 在 Python 中,可以使用 `asyncio` 的事件循环来管理协程的执行。import asyncioasync def task_one ( ) : print ( "Task One" ) async def task_two ( ) : print ( "Task Two" ) async def main ( ) : loop = asyncio. get_event_loop( ) loop. create_task( task_one( ) ) loop. create_task( task_two( ) ) await asyncio. sleep( 1 ) asyncio. run( main( ) ) 以上示例展示了异步 I/ O 操作、协程的定义和事件循环的使用。
`asyncio` 提供了更多丰富的功能,包括异步锁、异步队列、协程的并发控制等。
在实际应用中,异步编程可以提高程序的并发性能,特别是在处理大量 I/ O 操作时。
12.9 Redis数据类型、链接池、管道、事务,缓存设计与优化
1 redis数据库,非关系型(redis:内存数据库,所有数据放在内存中
2 数据类型:字符串,列表,字典(hash ),集合,有序集合
3 链接池:连接池的作用相当于缓存了多个客户端与redis服务端的连接,当有新的客户端来进行连接时,此时,只需要去连接池获取一个连接即可,实际上连接池就是把一个连接共享给多个客户端,可以说是广播,要用的话就去接收。
4 管道:非关系型数据库,本身不支持事务,redis默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。* * redis当中如何实现事务?(集群不支持,单机才支持)* *
具体实现:开启管道,把命令放进去,调用execute 依次执行管道中的所有命令,它的原理就是要么一次性都执行,要么都不执行,保证了事务* * 如果遇到访问的接口新增修改操作比较频繁怎么解决呢?如果是访问和新增修改同样频繁呢?* *
解决1 每次更新修改数据的时候,redis就删除一次缓存,下次访问的时候再去mysql中取
解决2 在序列化器中重写save 方法,每次新增修改数据就删除一次缓存,这样每次访问该接口的时候再去数据库中获取数据存到缓存中,拿到的数据都是最新的,首次访问缓存没有就去数据库中拿数据,再次访问的时候速度就快了。这种两种解决方式优点?
1 好处:加速读写
2 降低后端负载:后端服务器通过前端缓存降低负载,业务端使用redis降低后端mysql负载应用场景:
1 降低后端负载:对高消耗的sql ,join 结果集/ 分组统计的结果做缓存
2 加速请求响应:利用redis优化io响应时间
3 大量写合并为批量写:如计数器先redis累加再批量写入db
13 Celery进行异步任务、定时任务的处理,包结构封装与使用
Celery 异步任务框架:是一个简单、灵活且可靠的,处理大量消息的分布式系统,
专注于实时处理的异步任务队列,同时也支持任务调度应用场景:
异步任务:解决耗时任务, 将耗时操作任务提交给Celery 去异步执行,比如发送短信/ 邮件、消息推送、音视频处理等等
延迟任务:解决延迟任务(延迟多长时间,执行一个任务)
定时任务:定时执行某件事情,比如每天数据统计Celery 的架构由三部分组成,消息中间件(message broker )、任务执行单元(worker )和 任务执行结果存储(taskresult store )组成
1 消息中间件: Celery 本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成。包括,RabbitMQ , Redis 等等
2 任务执行单元: Worker 是Celery 提供的任务执行的单元,worker 并发的运行在分布式的系统节点中。
3 任务结果存储: Task result store 用来存储Worker 执行的任务的结果,Celery 支持以不同方式存储任务的结果,包括AMQP , redis 等
14 Git项目版本管理工具、docker部署。
工作中常用的几个git命令:
新增文件的命令:
git add file或者git add . 提交文件的命令:
git commit –m 或者 git commit –a查看工作区状况:
git status –s拉取合并远程分支的操作:
git fetch/git merge或者git pull查看提交记录命令:
git reflog我们公司开发用的gitee,有个主分支,我们大家开发都用一个分支,
所有人共用一个,它的好处是不存在合并时发生冲突,我们采用敏捷开发的
15 linux操作命令
cd :是切换到你要的目录里去
ls :是显示文件夹里面有些什么文件
mkdir :是创建文件夹
touch :是创建文件
mv :是移动某个文件到对应的文件夹下
vim :是用来做文本编辑的
tree :是显示目录层级
echo :相当于python的print,是输出的打印的意思
rm :是删除
16 生产者消费者模型
什么是生产者消费者模型?
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,
所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,
消费者不找生产者要数据,而是直接从阻塞队列里取,
阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。基于队列实现生产者消费者模型
"""
生产者:生产/制造东西
消费者:消费/处理东西的
该模型除了上述两个之外,还需要一个媒介
生活中的例子:做包子的将包子做好之后放在蒸笼(媒介)里面,买包子的去蒸笼里面拿
厨师做菜做完之后用盘子装着给消费者端过去
生产者和消费者之间不是直接做交互的,而是借助于媒介做交互
生产者(做包子的) + 消息队列(蒸笼) + 消费者(吃包子的)
"""
17 orm可以怎么优化?
批量创建 bulk_create( )
尽量不要在循环中操作 QuerySet
用values ( ) 或values_list( ) 只取需要的列的数据
使用iterator( ) 方法来获取数据,处理完数据就将其丢弃
select_related 查询外键
prefetch_related 处理一对多、多对多查询
18 数据库可以怎么优化?
索引、MySQL集群、负载均衡、读写分离
19 程序效率可以怎么优化?
只加载必要的模块,延迟加载
缓存优化
服务器架构优化
后端可以使用uwsgi
前端使用nginx 或者F5做负载均衡
20 mysql、redis高级
mysql主从同步: 业务、做高可用 两个nginx和两个tomcat两个mysql实现高可用,
避免 单点问题、中间使用keepalived监听
1 、实现服务器负载均衡
2 、通过复制实现数据的异地备份、提高数据库系统的可用性原理:
1. Master 数据库只要发生变化,立马记录到Binary log 日志文 件中
2. Slave数据库启动一个I/ O thread连接Master数据库,请求 Master变化的二进制日志
3. Slave I/ O获取到的二进制日志,保存到自己的Relay log 日志 文件中。
4. Slave 有一个 SQL thread定时检查Realy log是否变化,变化 那么就更新数据主从延迟:
1. 首先就是主库可以并发写入,从库只能通过单sql thread完成任务 (MySQL5. 7 之前)
2. MySQL主从之间的同步,本来就不是时时同步的,是异步的同步,也就是说,主库提交
事务之后,从库才再来执行一遍。
3. 在主库上对没有索引大表的列进行delete 或者update 的操作
4. 从库的硬件配置没有主库的好,经常忽略从库的重要性
5. 网络问题 '解决' : 1. 避免一些无用的IO消耗,可以上高转速的磁盘,SSD或者PCIE- SSD 设备2. 阵列级别要选择RAID10,raid cache策略要使用WB坚决不要WT。3. IO调度要选择deadline模式。4. 适当调整buffer pool的大小'redis非关系型键值对NoSQL数据库' AOF和RDB 'Redis持久化' :
RDB方案: 快照,某时刻完成备份、写日志、任何草错记录日志,要恢复数据、只要把 日志从新走一遍即可AOF方案: 客户端每写入一条命令,都记录一条日志,放到日志文件中、如果出现宕机、可以将数据完全恢复. 三种策略. 日志不是直接写到硬盘上,而是放在缓冲区,缓冲区根据一些策略、写到硬盘 aof重写: 本质就是把过期的,无用的,可以优化的命令,来优化,减少磁盘占用量,加快恢复速度主从复制: 高可用:
1 、副本库通过slaveof 127.0 .0 .1 6379 命令,连接主库、并发送sync给主库
2 、主库收到sync,触发BGSAVE, 后台保存RDB,发送给副本库
3 、副本库接受或会应用RDB快照、
4 、主库会陆续将中间产生的新的操作、保存并发送给副本库
5 、到此、主复制集就正常工作
6 、再此后、主库只要发生新的操作、都会以命令传播形式自动发送给副本库
7. 所有复制相关信息, 从info信息中都可以查到. 即使重启任何节点, 他的主从关 系依然都在.
8. 如果发生主从关系断开时, 从库数据没有任何损坏, 在下次重连之后, 从库发送 PSYNC给主库
9. 主库只会将从库缺失部分的数据同步给从库应用, 达到快速恢复主从的目的哨兵高可用:
1 多个sentinel发现并确认master有问题
2 选举触一个sentinel作为领导
3 选取一个slave作为新的master
4 通知其余slave成为新的master的slave
5 通知客户端主从变化
6 等待老的master复活成为新master的slave缓存雪崩: 大量缓存数据在同一时间过期、redis服务宕机、刚好大量用户请求、都无法在 redis中处理,都会直接访
问数据库造成高并发、导致数据库宕机,形成连锁反应导致服务器崩溃解决方案:
1 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
3 设置热点数据永远不过期。缓存预热: 业务刚上线的时候就提前把数据缓存起来、针对缓存雪崩的数据过期的一种方式
缓存击穿:业务被频繁访问,称为热数据大量请求访问的热数据过期了,无法从缓存中读取,直接访问数据库,引起数
据库压力瞬间增大,造成过大压力
解决方案:设置热点数据永远不过期。
缓存穿透:缓存穿透是用户访问数据不在缓存不在数据库、所有访问缓存的时候,缓存缺失、访问数据库、数据库也没有、没办法构建缓存,这样大量访问来的时候就会造成缓存穿透,这时的用户很可能是攻击者,攻击会导致数据库压力过大。解决方案:
1 限制非法请求(接口层增加校验,如用户鉴权校验,id做基础校验,id<= 0 的直接拦截)
2 缓存空值(将key - value 对写为key - null ,缓存有效时间可以设置短点,如30 秒
(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击)
3 利用布隆过滤器、
redis淘汰机制: 用一定的缓存丢失来换取内存的使用效率。
21 uWSGI和nginx的理解
uWSGI 是一个web 服务器,它实现了WSGI 协议,uwsgi 、http 等协议,
Nginx 中HttpUwsgiModule 的作用是与uWSGI 服务器进行交换,
WSGI 是一种Web 服务器网关接口,他是一个Web 服务器与web 应用通信的一种规范
WSGI 是一种通信协议
uwsgi 是一种线路协议而不是通信协议,在此常用语在uWSGI 服务器与其他网络服务器的数据通信
uWSGI 是实现了uwsgi 和WSGI 两种协议的Web 服务器
nginx 是一个开源的高性能的HTTP 服务器和反向代理:
1 . 作为web 服务器,它处理静态文件和索引文件效果非常高
2 . 它的设计非常注重效率,最大支持5 万个并发链接,但只占用很少的内存空间
3 . 稳定性高,配置简洁。
4 . 强大的反向代理和负载均衡功能,平衡集群中各个副武器的负载压力应用