知识体系库
Python
1.Python三大器:装饰器,生成器,迭代器
装饰器 : 它是Python特有的一种语法,基于闭包函数来实现的,本质也是一个函数,就是在不改变被装饰函数的源代码情况下为其增加新功能;
运用场景的话:最普遍的就是用户登入验证,然后还有记录日志,验证函数参数 : 简单举个例子,比如有一个输入年龄的参数, 年龄必须是正整数,那么我们就可以写一个装饰器,判断参数的值
迭代器 : 用来迭代取值的工具, 迭代就是一个重复的过程, 每次重复都是基于上一次的结果而进行的. 单纯的重复并不是迭代,可迭代对象 (iterable) : 在python中,但凡内置有 __iter__方法的对象,都是可迭代的对象;迭代器对象 (iterator) : 内置有__next__和 __iter__方法的对象, 就是迭代器对象, 可迭代对象执行__iter__得到的返回值就是迭代器对象
生成器 : 它本质上也就是一个迭代器,只不过是我们自己定义的,他里面的一个关键点就是yield关键字,只要碰到yield关键字,函数体将不再运行,需要你next()一下,玩法就是迭代器的玩法
yield和return的区别 : yield可以有多个,return只能有一个, 但站在功能的角度:都是返回值
2.反射
在运行过程中可以“动态(不见棺材不落泪)”获取对象的信息(数据属性和函数属性), 而在Python中,反射指的是通过字符串来操作对象的属性
3.Python 中的__new__
和__init__
的区别:
__new__是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象,是个静态方法。
__init__是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值,通常用在初始化一个类实例的时候。是一个实例方法。
4.上下文管理协议
上下文管理协议就是 with 语句, 为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__()和__exit__()方法
with 对象,触发对象的__enter__的执行
在with同一级别写代码, 脱离了with,就会执行 __exit__
5.深浅拷贝
# 浅拷贝:
不管多么复杂的数据结构,浅拷贝都只会copy一层,创建新对象,其内容是原对象的引用
# 深拷贝:
和浅拷贝对应,深拷贝拷贝了对象的所有元素,直到最后一层。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。
# 赋值:
就是将一个内存地址赋值给一个变量,本质就是一种对象的引用
6.新式类与经典类
# 新式类与经典类
Python 2 当中类分为新式类和经典类,如果有父类继承是object 就是新式类,继承其他类都不算,但是如果继承其他类,其他类中含有object,那就是新式类
Python 3中全部叫新式类
# 查找顺序
Python2 多继承当类是经典类时候,查找属性会按照深度优先的方法查找下去
Python3与Python2中的新式类,在多继承情况下会按照广度优先的顺序查找下去
7.继承,封装,多态,鸭子类型
# 继承
在 OOP 程序设计中,当我们定义一个新类的时候,新的类称为子类(Subclass),而被继承的类称为基类、父类或超类(Base class、Super class)。继承最大的好处是子类获得了父类的全部变量和方法的同时.
对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
# 多态
一种事物有多种形态,其中鸭子类型就是多态的体现,使用多态的好处:
1.增加了程序的灵活性以不变应万变,不论对象千变万化,使用者都是同一种形式去调用
2.增加了程序额可扩展性,通过继承基类创建了一个新的子类,使用者无需更改自己的代码.
# 鸭子类型:
因为python是动态强类型语言,不像Java和C++这种强类型语言,Python里实际上没有严格的类型检查。
继承一个类,子类中必须要有父类的方法, 就是只要某个对象具有鸭子的方法,可以像鸭子那样走路和嘎嘎叫,那么它就可以被其它函数当做鸭子一样调用。
在Python中可以使用abc这个模块里面的abc装饰器类强制性约束一个子类必须有父类的方法, 或者使用抛出异常的方式来进行限制, 但在python中推崇的是鸭子类型,其实我们完全可以不依赖于继承,只需要制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象,比起继承的方式,鸭子类型在某种程度上实现了程序的松耦合度
# 封装
封装就是一个约定,指将数据与具体操作的实现代码放在某个对象内部,使这些代码的实现细节不被外界发现,外界只能通过接口使用该对象,而不能通过任何形式修改对象内部实现,封装的两个层面:
第一个层面的封装:类就是一个袋子,这就是一种封装
第二个层面的封装:类中定义私有的,只有类内部使用,外部无法访问(比如_(杠) __(杠杠) )
# 封装的思想
使用封装能隐藏对象实现细节,使代码更易维护,
同时因为不能直接调用、修改对象内部的私有信息,在一定程度上保证了系统安全性。
类通过将函数和变量封装在内部,实现了比函数更高一级的封装。
8.元类实现底层原理
元类其实就是产生类的类,我们可以通过元类来拦截类的创建过程,这个地方我自己通过元类写过一个简易版本的ORM
首先ORM全称叫对象关系映射,能够让不会数据库操作的程序员通过面向对象的方法简单快捷的操作数据库,ORM有三层映射关系
* 类映射数据库的表
* 对象映射成数据库的表中的一条条记录
* 对象获取属性映射成数据库的表中的某条记录某个字段对应的值
具体做法就是在类创建过程中通过元类拦截它的创建,在类创建出来之前给类赋上表该有的属性表名,主键字段,其他普通字段
创建类的3个要素:类名,基类,类的名称空间 name, bases, dic
三个魔法方法:
__call__():如果有此方法,表示可调用,调用对象时自动触发
__new__():创建这个类实例的方法,只能用于从object继承的新式类
__init__():实例化一个类的时候第一个被调用的方法
通过__new__()控制类的创建过程
通过__call__()控制类的调用过程(对象的产生)
注意__call__的层次问题,上层__call__调起下层__new__和__init__
9.Python 中的GC机制
程序运行过程中会申请大量的内存空间,对于一些内存空间如果不及时清理的话会导致内存溢出,导致程序奔溃,Python中主要使用GC模块来处理内存溢出问题,主要运用了引用计数来追踪和垃圾回收,引用计数就是变量值被变量名关联的次数,引用计数一旦变为0,其占用的内存地址就应该被解释器的垃圾回收机制回收,引用计数存在一个致命的弱点,交叉引用(循环引用),定义两个列表,列表1的变量指向列表1,列表2的变量指向列表2,把列表2追加到l1中作为第二个元素,列表2的引用计数变为2,把列表1追加到l2中作为第二个元素,列表1的引用计数变为2,这样就l1与l2之间有相互引用,每一个对象的引用计数都不为0,因此这些对象所占用的内存永远不会被释放,所以循环引用是致命的, 所以Python引入了“标记-清除” 与“分代回收”来分别解决引用计数的循环引用与效率低的问题,标记的过程其实就是,遍历所有的GC Roots对象(栈区中的所有内容或者线程都可以作为GC Roots对象),然后将所有GC Roots的对象可以直接或间接访问到的对象标记为存活的对象,其余的均为非存活对象,应该被清除。清除的过程将遍历堆中所有的对象,将没有标记的对象全部清除掉。基于引用计数的回收机制,每次回收内存,都需要把所有对象的引用计数都遍历一遍,这是非常消耗时间的,于是引入了分代回收来提高回收效率,分代回收采用的是用“空间换时间”的策略。分代回收就是在历经多次扫描的情况下,都没有被回收的变量,gc机制就会认为,该变量是常用变量,gc对其扫描的频率会降低,分代指的是根据存活时间来为变量划分不同等级:新生代、青春代、老年代。
10.Python解释器的执行原理
执行 python程序后,将会启动 Python 的解释器,python解释器的编译器会将.py源文件编译(解释)成字节码生成PyCodeObject字节码对象存放在内存中。python解释器的虚拟机将执行内存中的字节码对象转化为机器语言,虚拟机与操作系统交互,使机器语言在机器硬件上运行。运行结束后python解释器则将PyCodeObject写回到pyc文件中。当python程序第二次运行时,首先程序会在硬盘中寻找pyc文件,如果找到,则直接载入,否则就重复上面的过程。
所以我们应该这样来定位PyCodeObject和pyc文件,我们说pyc文件其实是PyCodeObject的一种持久化保存方式。
pyc文件,文件中包含python的magic number(来说明编译时使用的python版本号)、源文件的mtime(使pyc和py文件保持同步)、编译出的code对象
注意:这里的字节码不是二进制代码,是Python的一种表现形式
计算机组成原理
1.文件系统
2.进程/线程
# 进程是资源分配的最小单位,线程是CPU调度的最小单位,比喻:工厂与流水线 过程的区别 进程:资源的申请与销毁,是资源的整合 线程:代码的执行过程 内存空间的区别 进程:内存空间彼此隔离 线程:同一进程下的多个线程共享资源 创建速度 进程:需要申请资源,开辟空间,速度较慢 线程:只是告诉操作系统一个执行方案,速度很快# 如何开启多进程 python实现多进程: 实现的方式是使用一个multiprocessing模块下的Process类 方式一 : 书写任务--->Process(target=[任务名],args=(参数,))--->p.start()-->p.join()括号内可以指定多少秒之后停止等待 方 式二 : 书写类继承Process--->里面书写run()方法--->p.start()--->p.join() # 如何开启多线程 Python threading模块下的Thread类 方式一 : 书写任务--->Thread(target=[任务名],args=(参数,))--->p.start()-->p.join() 方式二 : 书写类继承Thread--->里面书写run()方法--->p.start()--->p.join() Golang 使用go协程 # 进程内核态用户态 内核态 用户态 # 进程池和线程池 线程池: 线程池就是创建若干个可执行的线程放入一个池(容器)中,有任务需要处理时,会提交到线程池中的任务队列,处理完之后线程并不会被销毁,而是仍然在线程池中等待下一个任务 Python中开启线程池:threadpool(第三方),from concurrent.futures import ThreadPoolExecutor(自带) 进程池: 进程池的作用是在多个客户端并发请求时提高服务器的处理效率。进程池控制就是维护进程池的状态使其在一定范围之内,在本系统中,进程池有最大进程数和默认进程数(也是最小进程数),在这个范围内,进程池中正在处理客户请求的进程数占进程池中进程总数的比例,不能超过最大比例否则要求动态增加进程,不能低于最小比例否则要求动态减少进程
3.协程
# 什么是协程 协程能够保留上次一调用时的状态,能够进入上一次离开时所处的逻辑流的位置# 为什么用协程 协程的好处 无需线程上下文切换的开销 无需原子操作(不会被线程调度机制打断的操作)锁定以及同步的开销 方便切换控制流,简化编程模型 高并发+高扩展性+低成文:一个CPU支持上完的协程都不是问题,所以很适合高并发处理 协程的缺点 无法利用多核资源:协程的本质是单线程,需要和进程配合才能运行在多CPU上 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序# 怎么用协程 Python:gevent模块 Golang: go关键字
4.异步IO与IO多路复用
1. 同步,异步,阻塞,非阻塞的概念,烧水的例子,同步等待异步干别的事,阻塞守在旁边非阻塞过一会儿看一下# 什么是异步IO 发起一个IO操作(如:网络请求,文件读写等),比较耗时,不用等待结束,继续做其他事情,结束时会发来通知。# IO多路复用 单个process就可以同时处理多个网络连接的IO 优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销 select, poll, epoll都是I/O多路复用的具体的实现 select: 监视多个文件句柄的状态变化 程序会阻塞在select函数上,直到被监视的文件句柄中有一个或多个发生了状态变化 通知用户进程,然后由用户进程去操作IO poll: select函数有最大文件描述符的限制,一般1024个,而poll函数对文件描述符的数量没有限制 epoll: 监视的描述符数量不受限制,所支持的FD上限是最大可以打开文件的数目 I/O效率不会随着监视fd的数量增长而下降。epoll不同于select和poll轮询的方式,而是通过每个fd定义的回调函数来实现的,只有就绪的fd才会执行回调函数。
5.同步,异步,阻塞,非阻塞
# 同步异步: 同步是阻塞模式,异步是非阻塞模式。 同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返 回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去; 异步是指进程不需要一直等下去, 而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
计算机网络
1.五种网络I/O模型 :
阻塞IO模型 : 进程或线程等待某个条件,条件不成立则一直等待,条件成立则进行下一步非阻塞IO模型 : 与阻塞IO模型相反,应用进程与内核交互,目的未达到时不再一味的等待,而是通过轮询的方式不停的去询问内核数据有没有准备好IO复用模型 : IO复用模型是建立在内核提供的多路分离函数select基础之上的, 使用select函数可以避免非阻塞IO的轮询等待问题,它会添加一个监视,监视socket是否没激活,激活了select函数就返回,用户相乘就进行处理信号驱动IO模型 : 用的非常少,使用信号来通知进程异步IO模型 : 用户进程直接先进行系统调用,告知内核要进行IO操作,内核立即返回,用户进程立马可以去处理其他逻辑,当内核完成所有的IO之后,将会通知我们的程序,于是程序就可以对准备好的数据进行处理了
2.网络分层(osi七层协议)
应用层,表达层,会话层,传输层,网络层,链路层,物理层
3. TCP
# 三次握手,四次挥手 三次握手过程: 第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认 第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态。 第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手。 四次挥手 TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。 服务器关闭客户端的连接,发送一个FIN给客户端。 客户端发回ACK报文确认,并将确认序号设置为收到序号加1# 特点 TCP与UDP的区别 TCP:面向连接,可靠的,速度慢,效率低 UDP:无连接、不可靠、速度快、效率高# tcp滑动窗口 滑动窗口解决的是流量控制的的问题,就是如果接收端和发送端对数据包的处理速度不同,如何让双方达成一致 TCP是双工的,会话双方都可以同时接收和发送数据,双方都各自维护一个发送窗口和一个接收窗口 接收端的缓存传输数据给应用层,但这个过程不一定是即时的,如果发送速度太快,会出现接收端数据overflow,流量控制解决的是这个问题 # time-wait的作用 tcp释放连接的四次挥手后的主动关闭连接方的状态。 持续时间为2MSL,工程上为2min,2msl就是4min,但一般根据实际的网络情况进行确定。# TCP协议保证数据传输可靠性的方式主要有: 校验和 序列号 确认应答 超时重传 连接管理 流量控制 拥塞控制
4. UDP
# 特点 无连接 不可靠 面向报文 不提供阻塞和流量控制
5. HTTP/HTTPS/Websocket
# 四大特性 - 基于TCP/IP,作用于应用层之上 - 基于请求响应 - 无状态 cookie session token - 无连接# 数据格式 - 请求首行 方法字段 URL字段 HTTP协议版本 - 请求头 Accept: User-Agent:产生请求的浏览器类型; Refer:跳转前URL Content-Type:接收响应的数据类型 Cookie:存储于客户端扩展字段,向同一域名的服务端发送属于该域的cookie; - 请求体 要查询或提交的数据# HTTP1.0与1.1,HTTP2.0区别 - 1.0与1.1 长连接,HTTP1.1中默认开启长连接keep-alive 节约带宽,HTTP1.1支持只发送header信息,如果返回100才继续发body HOST域 缓存处理,HTTP1.1则引入了更多的缓存控制策略例 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码 - 1.1与2.0 多路复用,HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求 头部数据压缩,HTTP2.0使用HPACK算法对header的数据进行压缩 服务器推送,允许服务端推送资源给浏览器# HTTP与HTTPS区别 HTTP超文本传输协议 HTTPS是HTTP的安全版,HTTP下加入SSL层 https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。 http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。 http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。 http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。 - SSL/TSL 握手过程 客户端发送"client hello"给服务端,并包含客户端所支持的TSL版本和密码组合,还有一个"client random"随机字符串 服务端发送"server hello"给客户端,包含数字证书,服务器选择的密码组合和"server random"随机字符串 客户端校验服务端发来的证书 客户端向服务端发送另一随机字符串"premaster secret(预主密钥)",这个字符串是经过服务器的公钥加密的,只有对应的私钥才能解密 服务端使用私钥解密"premaster secret" 客户端和服务端均使用client random,server random和premaster secret,并通过相同的算法生成相同的共享密钥KEY 客户端发送经过共享密钥KEY加密的"finished"信号 服务端发送经过共享密钥KEY加密的"finished"信号 握手完成 - 为什么数据传输是用对称加密? 非对称加密的加解密效率是非常低的 只有服务端保存了私钥,一对公私钥只能实现单向的加解密# 浏览器输入网址发生了什么 输入网址—DNS域名解析—建立TCP连接—发送HTTP请求—服务器处理并返回结果—浏览器生成页面# websocket介绍 - http的痛点 http的生命周期,一个request,一个response http1.1的keep-live,可以发送多个request,但一个request还是对应一个response,response是被动的 - websocket是什么,为什么要使用 Websocket是一个持久化的协议 分析过程,long poll和轮循 ajax轮询:让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。 long poll:轮询,阻塞,保持连接,服务器开销大 - 怎么使用websocket Django中使用channels模块 channels运行于ASGI协议上,是区别于WSGI协议的一种异步网关接口协议,实现了websocket 官网推荐使用redis作为channel layer,所以要安装channels_redis gin框架使用websocket.Upgrader升级为ws
6. RPC
# 什么是rpc远程过程调用,简单的理解是一个节点请求另一个节点提供的服务# rpc实现的三个要素 Call ID 映射:将方法与唯一ID映射 序列化与反序列化:数据传输,跨语言间能互相识别 网络传输:可以基于TCP,UDP,HTTP
7. ARP协议
局域网内的通信,不仅需要源目IP地址的封装,也需要源目MAC的封装。在发送方需要目标MAC地址的时及时出手,通过"一问一答"的方式获取到特定IP对应的MAC地址,然后存储到本地【ARP缓存表】,后续需要的话,就到这里查找。arp封装,pc1 的ip1,mac2,要询问的pc2的ip2,mac? 这时候会将mac默认打包为全是f或ip全是255的格式(最大化广播范围)---> pc2收到广播,保存pc1映射到缓存,回复pc1,pc3,pc4等则会丢弃---> pc1收到后缓存,进行正确的打包属于那一层 功能最终是获取到MAC信息,服务于链路层 分层上和IP都基于Enthernet,属于网络层
8. ARQ协议
ARQ协议与滑动窗口机制的关系?自动重传请求 ( Automatic Repeat-reQuest , ARQ)是 OSI模型 中 数据链路层 和 传输层 的错误纠正协议之一。其利用确认和超时这两个机制,可以在不可靠服务的基础上实现可靠的信息传输。ARQ协议分等停ARQ协议和连续ARQ协议,连续ARQ协议采用了滑动窗口机制,后者又可分为后退N步协议和选择重传协议。
9. 拥塞控制有哪些算法
拥塞控制算法:慢开始、拥塞避免、快重传、快恢复。这些算法会根据网络不同的拥塞状况来搭配使用。慢开始算法:在一开始不清楚网络拥塞程度时,避免一开始就向网络中注入大量数据,由小到大逐渐增大拥塞窗口数值。cwnd(拥塞窗口) 初始值设为为 1,每经过一个传输轮次(transmission round),cwnd 加倍。(慢开始并不是指cwnd增长慢)。当拥塞窗口达到慢开始门限值 ssthresh,改用拥塞避免算法。(当cwnd = ssthresh时,既可使用慢开始算法,也可使用拥塞避免算法)。![](https://gitee.com/winlsr/resources/raw/master/img/image-20210717061407522.png)拥塞避免算法: 拥塞避免算法的思路是让 cwnd缓慢地增大,即每经过一个往返时间 RTT就把发送方的拥塞窗口 cwnd加1,而不是加倍。这样,拥塞窗口 cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(计时器超时,未收到确认),就要把慢开始门限 ssthresh设置为出现拥塞时的发送窗口值的一半(但不能小于2)。然后把拥塞窗口 cwnd 重新设置为 1,执行慢开始算法。![](https://gitee.com/winlsr/resources/raw/master/img/image-20210717064412551.png)快重传算法:快重传算法要求接收方在收到一个失序的报文段后就立即发出重复确认而不要等到自己发送数据时捎带确认。发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。(以便发送方及早知道丢失发生,及早进行重传)。与快重传配合使用的还有快恢复算法。![](https://gitee.com/winlsr/resources/raw/master/img/image-20210717064453713.png)快恢复算法:当发送方连续收到三个重复确认时,把 ssthresh门限减半。考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方认为现在网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法。![](https://gitee.com/winlsr/resources/raw/master/img/image-20210717064707907.png)
软件开发设计架构
1.设计模式
# 创建型模式 共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。# 结构型模式 共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。# 行为型模式 共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
2.MVC和MVT架构
# MVT : 是django中使用的设计架构: M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。 V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。 T 代表模板 (Template):负责如何把页面展示给用户(html)。# MVC : model,view,controller(控制器)低耦合,高内聚 M : 封装对数据库的访问,数据库数据的增删改查 v : 封装结果,返回html页面给用户 C : controller, 接收用户请求,处理业务逻辑,与model和view进行交互,返回结果