GIL全局解释锁
python解释器
- Cpython(C语言编写)
- Jpython(Java编写)
- Ppython(Python编写)
GIL全局解释锁
基于CPython来研究全局解释器锁,因为CPython的内存线程不是安全的
- GIL本质上是一个互斥锁
- GIL是为了阻止同一个进程内多个线程同时执行(并行)
- GIL的存在就是为了保证线程安全
注意:多个线程过来执行,一旦遇到IO操作,就会立马释放GIL解释器锁,交给下一个先进来的线程
多线程的作用
计算密集型程序
在单核情况下,若一个任务需要10s
开启进程,消耗资源大,执行4个进程需要40s
开启线程,消耗资源小,执行4个线程需要40s
在多核情况下,若一个任务需要10s
- 开启进程,并行执行,效率较高,执行4个进程需要10s
- 开启线程,并发执行,效率较低,执行4个线程需要40s
IO密集型程序
在单核情况下,若一个任务需要10s
开启进程,消耗资源大,执行4个进程需要40s
开启线程,消耗资源小,执行4个线程需要40s
在多核情况下,若一个任务需要10s
- 开启进程,并行执行,效率小于线程,因为遇到IO会立即切换CPU执行权限,执行4个进程需要10s = 开启进程的额外时间
- 开启线程,并发执行,效率高于进程,执行4个线程需要40s
死锁现象
死锁是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程 ,解决方式就是递归锁
递归锁
递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。
信号量
信号量Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()
注意: 与进程池是完全不同的概念,进程池Pool(4),最大只能产生4个进程,而且从头到尾都只是这四个进程,不会产生新的,而信号量是产生一堆线程/进程
线程队列
线程队列
queue队列:使用import queue
,用法与进程Queue一样
先进先出
FIFO队列: 先进先出 class queue.Queue(maxsize=0)
后进先出
LIFO队列: 后进先出 class queue.LifoQueue(maxsize=0 )
优先级队列
优先级队列: 根据参数内,数字的大小进行分级,数字值越小,优先级越高class queue.PriorityQueue(maxsize=0)
put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高