2.并发编程
2.3 进程:Process类
2.3.1 args:给子进程传递参数
传递一个参数:
子进程无法传递返回值,可以通过写入文件传递数据
2.3.2 同时开启多个子进程
验证多个子进程并发:start()是异步方法,不等待执行结果,直接执行后续代码
使用循环开多个并发进程
2.3.3 join():产生同步阻塞
Process对象.join()。制造同步阻塞,直到对象的进程执行完毕
增加p.join(),等待时间随机。出现“所有邮件发送完毕”仍然不在最后
循环检测所有对象的进程都已经执行完成。
2.3.4 各个进程之间的数据是隔离的
子进程向父进程传递数据的最好方法是:通过写文件传递数据
2.3.5 使用多进程实现并发socketserver
2.3.6 创建子类对象开启进程(面向对象)
传参:使用__init__方法接收参数,还要执行super().init()调用父类的方法
2.3.7 进程的常用属性
start、pid、ident、name、is_alive、terminate
2.3.8 daemon:守护进程
主进程会等待所有子进程结束,是为了回收子进程的资源。
守护进程会等待主进程的代码执行结束后再结束,而不是等待主进程结束,主进程要在守护进程结束后,回收守护进程的资源。执行到代码结束是一个比较靠后的合理时间。
主进程代码结束,守护进程就结束,和其它子进程的执行进度无关。
在start进程之前设置守护进程:Process对象.daemon=True
结果:
p1.start后开始每秒打印一个“in son1”,三秒后主进程代码执行完毕,共打印3条
p2.start后开始每秒打印一个“in son2”,打印5次耗时5秒
如果希望p1在p2结束后再停止,可以在代码末尾添加p2.join()制造阻塞
结果:
应用:可以使用守护进程制作心跳检测,主程序活着就定期发送心跳信息,程序挂了守护进程也就结束了,不再发送心跳信息
2.3.9 Lock():互斥锁
1)模拟买票系统
在休眠0.1秒时,大家都买到票了。数据没有加锁,大家并发操作,导致数据错误
2)模拟买票系统增加Lock互斥锁
Lock互斥锁:不能在同一进程中连续acquire多次。只能release后,再acquire。
加锁部分:同步阻塞,会降低运行效率,保证数据安全
使用with lock,简化代码:代替acquire和release,并能够处理异常
2.4 进程之间通信(IPC)
2.4.1 进程之间通信(IPC):Inter Process Communication
1)基于文件通信:
适用同一台机器上的多个进程之间的通信。
(1)socket中family=AF_UNIX可以使用本地socket文件来通信
(2)Queue队列
2)基于网络通信:
适用同一台机器或多台机器上的多进程间通信。
第三方工具(消息中间件):
(1)memcache
(2)redis
(3)rabbitmg
(4)kafka
2.4.2 Queue:进程队列
1)Queue进程队列:基于socket、pickle(文件读写)、Lock(保证数据安全)实现,socket中family=AF_UNIX可以使用本地socket文件来通信
2)piple管道:基于socket、pickle(文件读写)实现,没有加锁,数据不安全,已经很少使用。
2.4.3 生产者消费者模型(重要)
1)生产者消费者模型:
生产者消费者模型就是通过一个容器来解决生产者和消费者的强耦合问题。
生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
目的:让生产者和消费者达到效率最大化
2)生产者消费者升级版:
3)异步阻塞和生产者消费者模型
4)生产者消费者模型-将网页写入文件
2.4.4 Manager类:数据共享
Python中提供了强大的Manager类,专门用于实现多进程之间的数据共享。
Manager类是数据不安全的。
1)进程间数据隔离
2)使用Manager类实现数据共享
3)使用Lock保护Manager类数据
4)with Manager() as m