1. 猴子补丁
功能: 拥有在模块运行时替换的功能
例如: 将一个函数对象赋值给另外一个函数对象 , 把函数原本执行的功能给替换了
# 案例
import json
import ujson # pip3 install ujson
def monkey_patch():
json.__name__ = ujson.__name__
json.dumps = ujson.dumps
json.loads = ujson.loads
2. 垃圾回收机制
python 程序在运行时,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量,计算完成后,再将结果输出到永久性存储器中。
但是当数据量过大,或者内存空间管理不善,就很容易出现内存溢出的情况,程序可能会被操作系统终止。
而对于服务器这种用于永不中断的系统来说,内存管理就显得更为重要了,不然很容易引发内存泄漏
引用计数机制: 一个变量值的引用计数为0时 , 才会被当做垃圾回收
问题1: 循环引用 => 内存泄漏
标记清除算法 (mark-sweep)
问题2: 效率问题
分代回收 (generational)
3. 进程
1. 进程简介
1. 程序
程序就是一堆代码文件
优化程序效率的核心法则: 降低I/O操作 (内存 => 本地硬盘 => 网络I/O)
2. 进程的概念
进程是一个抽象的概念 , 进程就是正则运行的程序 , 它是操作系统中 , 资源分配的最小单位
资源分配: 分配的是cpu和内存等物理资源
进程指的是程序的运行过程 , 进程是操作系统最核心的概念 , 进程号是进程的唯一标识 (PID)
同一程序执行两次之后是两个进程
进程彼此之间的内存空间隔离 (而且是物理隔离) , 数据彼此隔离 , 通过 socket 通信
进程的创建
windows : CreateProcess
linux : fork
3. 补充
串行: 多个任务依次运行 , 一个运行完毕再运行下一个
并行: 多个进程是真正意义上一起运行 , 指的是多个CPU同一时间不停执行多个程序
并发: 看起来是同时运行的 , 本质还是一个个的运行 , 指的是一个CPU同一时间不停执行多个程序
4. CPU的进程调度方法
先来先服务 fcfs (first come first server) : 先来的先执行
短作业优先算法: 分配的cpu多 , 先把短的算完
时间片轮转算法: 每一个任务就执行一个时间片的时间 , 然后执行其他的
多级反馈队列算法
越是时间长的 , CPU 分配的资源越少 , 优先级靠后
越是时间短的 , CPU 分配的资源越多
5. 进程三状态
1. 就绪状态 (Ready)
只剩下CPU需要执行 , 其他所有资源都已分配完毕 , 称为就绪状态
2. 执行状态 (Running)
CPU开始执行该进程时称为执行状态
3. 阻塞状态 (Blocked)
**由于等待某个事件发生而无法执行时 , 便是阻塞状态 , CPU执行其他进程 **
例如: 等待I/O完成input 申请缓冲区不能满足等 …
6. 同步 异步 / 阻塞 非阻塞
场景在多任务当中:
同步: 必须等我这件事干完了,你再干 , 只有一条主线 , 就是同步
异步: 没等我这件事干完 , 你就在干了 , 有两条主线 , 就是异步
阻塞: 比如代码有了 input , 就是阻塞 , 必须要输入一个字符串 , 否则代码不往下执行
非阻塞: 没有任何等待 , 正常代码往下执行
**特点: **
同步阻塞: 效率低 , CPU利用不充分
异步阻塞: 比如socketserver , 可以同时连接多个 , 但是彼此都有 recv
同步非阻塞: 没有类似input的代码 , 从上到下执行 , 默认的正常情况代码
异步非阻塞: 效率是最高的 , CPU过度充分 , 过度发热
7. 守护进程
功能: 给子进程贴上守护进程的名字 , 该进程会随着主进程代码执行完毕而结束 (守护主进程)
1. 守护进程会在主进程代码执行结束后就终止
2. 守护进程内无法再开启子进程 , 否则抛出异常
8. 操作系统
1. 操作系统的概念
操作系统就是一个协调 , 管理 , 控制计算机硬件资源和软件资源的控制程序
操作系统的组成: 系统接口 操作系统内核
2. 操作系统的作用
1. 隐藏丑陋复杂的硬件接口,提供良好的抽象接口
2. 管理、调度进程,并且将多个进程对硬件的竞争变得有序
3. 多道技术
多道技术中的多道指的是多个程序 , 多道技术的实现是为了解决多个程序竞争或者说共享一个资源 (比如 CPU) 的有序调度问题 , 解决方式即多路复用 , 多路复用分为时间上的复用和空间上的复用
空间上的复用: (复用内存的空间)
将内存分为几部分 , 每个部分放入一个程序 , 这样同一时间内存中就有了多道程序
1. 多个程序的代码都存入内存
2. 内存空间是物理隔离的
时间上的复用: (复用CPU的时间)
当一个程序在等待I/O时,另一个程序可以使用CPU ,如果内存中可以同时存放足够多的作业 , 则CPU的利用率可以接近100% , 类似于我们小学数学所学的统筹方法
CPU的切换
1. 任务的运行遇到I/O阻塞 => 提升效率
2. 任务占用CPU时间过长 => 降低效率
作用:
操作系统采用了多道技术后 , 可以控制进程的切换 , 或者说进程之间去争抢CPU的执行权限 , 这种切换不仅会在一个进程遇到I/O时进行 , 一个进程占用CPU时间过长也会切换 , 或者说被操作系统夺走CPU的执行权限
如果我们的核心目标是想让多个任务并发起来: 那么无论是否遇到I/O都应该让CPU在多个任务之间切换起来
如果我们的核心目标是想让多个任务的运行效率提升: 我们应该只控制一个任务在遇到I/O情况下切换到另外一个任务
2. 进程的使用
Process 类的介绍
# 创建进程的类
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
# 参数介绍
group参数未使用,值始终为None
target表示调用对象,即子进程要执行的任务
args表示调用对象的位置参数元组,args=(1,2,'egon',)
kwargs表示调用对象的字典,kwargs={
'name':'egon','age':18}
name为子进程的名称
# 方法介绍
p.start():启动进程,并调用该子进程中的p.run()
p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True
p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
# 属性介绍
p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
p.name:进程的名称
p.pid:进程的pid
p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
1. 进程的基本使用
'''
ps -aux 查看进程号
ps -aux | grep 2860
kill -9 2860 杀死进程
'''
# 获取当前进程 ip 子进程
res = os.getpid()
print(res)
# 获取当前进程的父进程
res = os.getppid()
print(res)
import os,time,random
from multiprocessing import Process
# 1. 进程的基本使用
def func():
print("1.子进程id>>{},2.父进程id>>{}".format(os.getpid(),os.getppid()))
# 为了解决 windows 和 linux 系统的兼容问题 , if __name__ == '__main__' 必须加上 , 否则报错
"""
由于Windows没有fork,多处理模块启动一个新的Python进程并导入调用模块
如果在导入时调用Process(),那么这将启动无限继承的新进程(或直到机器耗尽资源)
这是隐藏对Process()内部调用的原,使用if __name__ == “__main __”
这个if语句中的语句将不会在导入时被调用
"""