并发编程的目标是让服务端能够支持高并发+高性能
一、多进程
1、进程
正在执行的过程/程序,程序其实就是一堆文件
进程是一个抽象的概念,进程其实是一个资源单位,这个概念起源于操作系统
操作系统的两大作用:
1)、把复杂硬件操作都封装成接口,提供给应用程序使用
2)、把进程对硬件的竞争变得有序
2、操作系统的多道技术:
在单个CPU的情况下实现多个进程并发执行的效果
1)、空间上的复用
多道程序复用内存的空间,进程与进程之间的内存是互相隔离的,而且这种隔离是物理级别的
2)、时间上的复用
多道程序复用CPU的空间:CPU遇到IO操作要切换(提升效率),一个进程占用CPU时间过长也切换(降低效率)
3、串行、并发、并行的区别
串行:按照固定的顺序一个一个的运行,一个任务完完整整的执行完毕后才运行下一个任务
并发:多个任务看起来是同时运行的,并发实现的本质是切换+保存的状态
并行:真正意义上的同时运行,一个CPU同一时刻只能做一件事,只有多核才能同时做多件事,即并行的效果,并行也属于并发
4、进程的三种状态
运行、就绪(合称为非阻塞)、阻塞
5、开启子进程的两种方式
通过multiprocessing模块中的Process类直接调用和继承式调用
multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件
在windows中,Process()必须放到if __name __ == 'main':下
.start() 向操作系统发送请求,操作系统会申请内存空间,然后把父进程的数据拷贝给子进程,作为子进程的初始化
.run() 进程启动时运行的方法
.join() 父进程等待子进程结束,让父进程在原地等,在子进程结束后回收
.terminate() 强制终止进程
6、守护进程
主进程代码运行完毕,守护进程就会结束
obj.daemon=True 把子进程变成守护进程
7、互斥锁
互斥锁用来将并发变成一个一个的执行,牺牲了效率而保证了数据安全
使用multiprocessing模块中的Lock类:
lock.acquire()加锁必须是一次,然后lock.release()释放一次,才能继续下一次的lock.acquire(),不能连续的lock.acquire()
互斥锁和join的相同和区别:
相同:二者的原理都是一样,都是将并发变成串行,从而保证有序
区别:1)、join是按照人为制定的顺序执行,而互斥锁是所用进程平等地竞争,谁先抢到谁执行
2)、互斥锁可以让一部分代码(修改共享数据的代码)串行,而join只能将代码整体串行
8、进程间通信(IPC)机制
进程之间通信必须找到一种介质,该介质必须满足:
1)、是所有进程共享的;
2)、必须是内存空间
3)、可以自动处理好锁的问题
使用multiprocessing模块中的Queue类可以同时满足上面的3种条件
1)、队列用来存放进程之间沟通的消息
2)、maxsize的值超过了内存的限制就变得毫无意义
9、生产者消费者模型
生产者消费者模型是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,队列存放的是一些消息。
该模块中包含两类重要的角色:
生产者:将负责造数据的任务比喻为生产者
消费者:接收生产者造出的数据来做进一步的处理,该类任务被比喻为消费者
实现生产者消费者模型的三要素:生产者、消费者、队列
什么时候用生产者消费者模型:
程序中出现明显的两类任务:负责生产的任务和负责处理的任务
该模型的好处:
1)、实现了生产者和消费者解耦和
2)、平衡了生产力与消费力,即生产者可以一直不停的生产,消费者可以不停的处理,因为二者不再沟通,而是通过队列沟通
在生产者生产完毕后,往队列的末尾添加一个结束信号None
在生产者生产完毕后,拿到队列中元素的总个数,然后直到元素总数变为0,.join()这一行代码才算运行完毕。.join()一旦结束就意味着队列 确实被取空,消费者已经把数据都取干净了
二、多线程
线程指的是一条流水线的工作过程
进程是资源单位,线程是执行单位,一个进程内自带一个线程
1、进程与线程的区别:
1)、同一个进程内的线程共享该进程内的资源,不同进程内的线程资源是隔离的
2)、创建线程的开销比创建进程要小的多
2、开启线程的两种方式:
通过threading模块中的Thead类直接调用和继承式调用
3、守护线程
4、互斥锁
5、死锁与递归锁
6、信号量
7、GIL全局解释器锁
GIL本质是一把互斥锁,是加在解释器身上的,同一个进程内所有线程都需要先抢到GIL锁,才能执行解释器锁
优点:保证Cpython解释器内存管理的线程安全
缺点:同一个线程内所有的线程同一时刻只能有一个执行,也就是说Cpytnon解释器的多线程无法实现并行
计算密集型应该用多进程,IO密集型应该用多线程
8、进程池与线程池
池是用来限制并发的任务数目,限制计算机在一个可承受的范围内并发的执行任务
并发的任务属于计算密集型的用进程池,属于IO密集型的用线程池
9、阻塞与非阻塞,同步与异步
阻塞与非阻塞指的是程序的两种运行状态
阻塞:遇到IO就发生阻塞,程序一旦遇到阻塞操作就会停在原地,并且立刻释放CPU资源
非阻塞(就绪态或运行态):没有遇到IO操作,或者通过某种手段让程序即便是遇到IO操作也不会停在原地,执行其他操作,力求尽可能多的占有CPU
同步与异步指的是提交任务的两种方式
同步调用:提交任务后,就在原地等待,直到任务运行完毕后,拿到任务的返回值,才继续执行下一行代码
异步调用:提交任务,不在原地等待,直接执行下一行代码
10、异步+回调机制
11、线程queue
12、线程Event
三、协程
单线程下实现并发
四、IO模型
IO模型解决的是网络IO
网络IO分为wait data和copy data两个阶段
1、阻塞IO
2、非阻塞IO
3、多路复用IO
处理来自多个程序发起的多个(多个即多路)共享(共享即复用)资源的请求,简称多路复用
多路复用IO比阻塞IO效率低
4、异步IO
异步IO的效率最高
五、socketserver模块