GIL定义:
GIL全局解释锁
定义:解释器通过这种机制获取全局解释锁来限制同一个时间点只允许一个线程执行,即使在多核环境下.
当初设计的原因
解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁,解决资源竞争;
现在存在的原因
量库代码开发者已经重度依赖GIL而非常难以去除了
python单线程和多线程分别用于完成什么工作?
IO密集型:
涉及到网络,磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务大部分是等待IO操作完成(因为IO的速度远低于CPU和内存的)
CPU密集锁:
CPU密集型也称为计算密集型,任务特点是要进行大量的计算,消耗CPU资源,比如计算圆周率,对视频进行高清解码等,全靠CPU的运算能力;
python线程的切换:
对于有io操作的线程,
当一个线程在做io操作的时候,因为io操作不需要cpu,所以,这个时候,python会释放python全局锁,这样其他需要运行的线程就会使用该锁。
对于cpu密集型的线程,
比如一个线程可能一直需要使用cpu做计算,那么python中会有一个执行指令的计数器,当一个线程执行了一定数量的指令时,该线程就会停止执行并让出当前的锁,这样其他的线程就可以执行代码了。
所以在写多任务的程序时:
计算密集型程序:一般采用进程,可以充分的利用CPU的资源
IO密集型程序:可以采用线程、协程。(在IO操作的等待的时间过长,会释放GIL锁,然后供其他线程使用)
python GIL的概念:
GIL,全局解释器锁(global interpreter lock),它不是python语言的特性,而是python默认的解析器cpython的特性cpython要求每个线程必须先获取GIL锁,才能执行线程中的代码
目的:
解决多线程同时竞争解析器程序的全局变量而出现的线程安全问题
不足:
在多线程中不能充分利用多核cpu 原因是一个进程只存在一把gil锁,当在执行多个线程时,内部会争抢gil锁,这会造成当某一个线程没有抢到锁的时候会让cpu等待,进而不能合理利用多核cpu资源
对python多线程有什么影响?
1…GIL:全局解释器锁,每个线程执行过程中先获取GIL,
保证相同时刻只有一个线程可以执行代码;
2. 由于GIL的存在,会影响多线程不能利用多核CPU资源(原因是一个进程只存在一把gil锁,当在执行多个线程时,内部会争抢gil锁,这会造成当某一个线程没有抢到锁的时候会让cpu等待,进而不能合理利用多核cpu资源),通过多进程方式可利用多个CPU资源
线程释放GIL锁的情况:
1.在IO操作等可能会引起阻塞的system call之前,可以暂时释放GIL,但在执行完毕后,必须重新获取GIL
2.Python 3x使用计时器(执行时间达到阈值后,当前线程释放GIL)
如何解决GIL问题:
- 换语言, 在处理多线程代码时,用其他语言代码,比如用
c或者java - 换解析器,比如换jpython
- 业界常用的方案: 多进程+多协程方法
4.python使用多进程是可以利用多核的CPU资源的;
一个单线程抓取网页的程序,与一个多线程抓取网页的程序哪个性能更高,并解释原因?
- 多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁,这样在线程阻塞情况下,可以执行其他线程中的代码
- 多线程爬取比单线程性能有提升,因为遇到IO阻塞会自动释放GIL锁
单线程、多线程、多进程执行分析
- 单线程: 双核cpu使用率50%
- 多线程:双核cpu使用率50%
- 多进程:双核cpu使用率100%
为什么上述的多线程不是占用1个核100%呢?而是两个核都差不多是50%:
linux的进程调度系统内,当python多线程切换时候,linux
调度子系统会兼顾多核的负载情况,linux会把多个线程平均分布在多核上跑,这样不
会导致单个核负载过盛。但是这个并不会让python多线程在多核上并行。