GIL锁
1.GIL锁
- 全局解释器锁,就是一个把互斥锁,将并发变成串行,同一时刻只能有一个线程使用共享资源,牺牲效率,保证数据安全,也让程序员避免自己一个个加锁,减轻开发负担
- 带来的问题
- 感觉单核处理IO阻塞的多线程,与多核处理IO阻塞的多线程效率差不多,实际上由于cpu遇到IO问题会将线程挂起,切换到其他线程,多出的时间仅仅是多在切换的时间,两者效率差不多
- 多核的前提下:如果任务IO密集型,多线程并发,避免开进程占用资源,若果是任务计算密集型:多进程并发,可充分利用多核优势
2.普通的Lock锁与GIL锁的关系
-
GIL保护的是解释器级别的数据,例如垃圾回收的数据,Lock保护的是自己开发的程序的数据
-
GIL锁可以看做执行权限,哪个线程先抢到,就先执行,当要IO阻塞或者等待自己加Lock锁释放时,自动解除GIL锁,其他线程开始抢执行权限,依次类推,
-
产生原因
-
因为Python解释器帮你自动定期进行内存回收,你可以理解为python解释器里有一个独立的线程,每过一段时间它起wake up做一次全局轮询看看哪些内存数据是可以被清空的,此时你自己的程序 里的线程和 py解释器自己的线程是并发运行的,假设你的线程删除了一个变量,py解释器的垃圾回收线程在清空这个变量的过程中的clearing时刻,可能一个其它线程正好又重新给这个还没来及得清空的内存空间赋值了,结果就有可能新赋值的数据被删除了,为了解决类似的问题,python解释器简单粗暴的加了锁,即当一个线程运行时,其它人都不能动,这样就解决了上述的问题, 这可以说是Python早期版本的遗留问题。
-
3.进程池线程池
- 进程池:放置进程的一个容器,
- 线程池,当时线程的一个容器,用来限制系统中执行的线程的数量
- 假设进来5000个线程,则会同时开启5000个线程,耗时较高,如果使用线程池,当线程结束后,该线程不消失,继续处理下一个任务,所以只需要开启较少的线程
- 线程即是开销小,电脑也不能无限的开线程,我们应该对线程和进程做数量的限制,在计算机能承受的最大情况下,尽可能的多开进程和线程
- 进程池默认进程数为None,此时进程数默认为os.cpu_count(),也就是cpu的个数
- 线程池默认的线程数为None,此时线程的默认个数为cpu的个数*5