今天学习了JIR、进程池和线程池
GIL:Global Interpreter Lock
全局解释器锁
锁的作用:为了避免资源竞争造成数据错乱
python程序的执行过程
1.启动解释器进程 python.exe
2.解析你的py文件并执行它
每个py程序中殴斗必须有解释器参与 解释器其实就是一堆代码
相当于多个线程要调用同一个解释器代码 共享意味着竞争 竞争就要出事
给解释器加互斥锁
python中内存管理依赖于 GC一段用于回收内存的代码) 也需要一个线程
除了你自己开的线程 系统还有一些内置线程 就算你的代码不会去竞争解释器 内置线程也可能会竞争
所以必须加上锁
当一个线程遇到了I/O 同时解释器也会自动解锁 去执行其他线程 cpu会切换到其他程序
解释器加锁以后
将导致所有线程只能并发 不能达到真正的并行 意味着同一时间只有一个CPU在处理你的线程给你的感觉是效率低
代码执行有两种状态
阻塞 i/o 失去CPU的执行权 CPU等待IO完成)
非阻塞 代码正常执行 比如循环一千万次 中途CPU可能切换 很快会回来 CPU在计算)
假如有32核CPU 要处理一个下载任务 网络速度慢 只有100kb/s 文件大小为1024kb
如果你的代码中IO操作非常多 cpu性能不能直接决定你的任务处理速度
在IO密集的程序中 CPU性能无法直接决定程序的执行速度 python就应该干这种活儿
在计算密集的程序中 CPU性能可以直接决定程序的执行速度
计算密集测试
from multiprocessing import Process import time #计算密集任务 def task1): sum = 1 for i in range10000000): sum *=i def task2): sum = 1 for i in range10000000): sum *=i def task3): sum = 1 for i in range10000000): sum *=i def task4): sum = 1 for i in range10000000): sum *=i def task5): sum = 1 for i in range10000000): sum *=i def task6): sum = 1 for i in range10000000): sum *=i if __name__ == '__init__': # 开始时间 st_time = time.time) # 多进程情况下 p1 = Processtarget = task1) p2 = Processtarget = task2) p3 = Processtarget = task3) p4 = Processtarget = task4) p5 = Processtarget = task5) p6 = Processtarget = task6) p1.start) p2.start) p3.start) p4.start) p5.start) p6.start) p1.join) p2.join) p3.join) p4.join) p5.join) p6.join) printtime.time)-st_time) ''' 1.05321354643464 '''
IO密集测试
from threading import Thread import time #计算密集任务 def task1): time.sleep3) def task2): time.sleep3) def task3): time.sleep3) def task4): time.sleep3) def task5): time.sleep3) def task6): time.sleep3) if __name__ == '__main__': #开始时间 st_time = time.time) #多线程情况下 t1 = Threadtarget = task1) t2 = Threadtarget = task2) t3 = Threadtarget = task3) t4 = Threadtarget = task4) t5 = Threadtarget = task5) t6 = Threadtarget = task6) t1.start) t2.start) t3.start) t4.start) t5.start) t6.start) t1.join) t2.join) t3.join) t4.join) t5.join) t6.join) printtime.time - st_time) ''' 3.0035946873164 '''
二、进程池
进程池就是一个装进程的容器
为什么出现
当进程很多的时候方便管理进程
什么时候用?
当并发量特别大的时候 例如双十一
很多时候进程是空闲的 就让他进入进程池 让有任务处理时才从进程池取出来使用
进程池使用
ProcessPoolExecutor类
创建时指定最大进程数 自动创建进程
调用submit函数将任务提交到进程池中
创建进程是在调用submit后发生的
总结一下:
进程池可以自动创建进程
进程限制最大进程数
自动选择一个空闲的进程帮你处理任务
三、线程池
和进程池差不多,使用的是ThreadPoolExcecutor类