进程池与线程池,协程
一:引子:基于多线程实现套接字服务端并发。如图1:
但是如图1这种基于多线程实现套接字服务端并发实现后,如果开启的客户端过多,那么服务端就会不停地开启线程,
占用内存空间,所以不能这样无限的去开启线程 / 进程,所以需要采取一种措施,把并发的线程数 / 进程数控制在一定数量
之内,从而阻止无限的去开启线程 / 进程,这样就引出了进程池与线程池。
二:进程池与线程池:池就是一个容器,来盛放线程/进程。
进程池:
所以,当并发的任务数超过了机器所能承受的范围,就需要这个池,也就是这个容器来限制并发的
个数(线程数/进程数),至于池里面是盛放进程还是线程,这就取决于并发的任务是IO密集型还是计算密集型。:
1:如何使用进程池以及线程池:
通过导入模块from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor,简单的
进程池就造好了,如图2:
进程池完成后就需要提交任务,所以,提交任务的两种方式:
①:同步调用(如图4):提交完一个任务之后,就在原地等待,等待任务完完整整地运行完毕拿到结果后,
再执行下一行代码,会导致任务是串行执行的。
②:异步调用(如图3):提交完一个任务之后,不在原地等待,而是直接执行下一行代码,会导致任务是
并发执行的,异步调用通常和回调函数一起配合使用,结果(future对象)会在任务运行完毕后自动传给回调函数。
但是(如图3)这种情况异步提交之后,没有显示结果,可以通过异步提交之后会有一个返回对象(如future),
这个对象下面有一个绑定方法result,来进行查看,这种形式就成了串行,也就成了同步调用(如图4)。
而异步提交只提交任务,不立即拿结果,而是任务全部提交完之后,再拿结果(如图5)。这就需要
利用shutdown(wait=True)来实现,它的含义是:关闭进程池的入口,并且在原地等待进程池内所有任务运行完毕。
进程池:最终如图6:
线程池:如图7,和进程池类似,进程池是主进程操作回调函数,线程池是谁是空闲状态谁就操作回调函数。
三:协程
1:协程就是在单线程下实现并发
并发(多个任务看起来是同时执行就是并发),并发的核心:切换+保存状态
注意:协程是程序员自己定义出来的东西,操作系统里只有进程和线程的概念(操作系统调度的是线程)
当然,单线程下实现并发并不是都有意义的,只有在单线程下实现多个任务间遇到IO就切换就可以降低单线程的IO时间,
从而最大限度地提升单线程的效率。
2:基于yield实现协程:(如图8)这种yield实现的协程,并不是遇到IO就切换,效率反而会降低了。由于yield不能
实现监测IO,遇到IO就进行切换的功能。所以现在需要找到一种方案,既能够管理单线程下的多个任务,又能识别
单线程任务下的IO行为,实现遇到IO就自动能切换到另一个任务去运行,从而实现单线程下的并发,提升效率。
这就是gevent模块。
3:gevent模块:gevent模块的使用如图9:
4:利用gevent模块实现单线程下并发的套接字通信,如图10: