python GIL
在多线程环境中,Python虚拟机按照以下方式执行。
1.设置GIL。
2.切换到一个线程去执行。
3.运行。
4.把线程设置为睡眠状态。
5.解锁GIL。
6.再次重复以上步骤。
- 线程锁
用theading.Lock()创建一个lock的实例。
在线程启动之前通过lock.acquire()加加锁,在线程结束之后通过lock.release()释放锁。
这层锁是用户开的锁,就是我们用户程序的锁。跟我们这个GIL没有关系,但是它把这个数据相当于copy了两份,所以在这里加锁,以确保同一时间只有一个线程,真真正正的修改这个数据,所以这里的锁跟GIL没有关系,你理解就是自己的锁。
在用户层面加锁,使程序变成串行了,那我们在什么情况下用呢?
1、我们在程序中间不能有sleep,因为程序变成串行,这样你再sleep,程序执行的时间就会变长。# time.sleep(0.1) # 注意了sleep的时候是不占有cpu的,这个时候cpu直接把这个线程挂起了,此时cpu去干别的事情去了
2、我们使用的时候确保数据量不是特别大,如果数据量大,也会影响我们的执行效率。
3、如果你程序结束时,不释放锁的话,而且程序又是串行的,则就是占着坑,那永远在那边等着,所以最后需要释放锁。
- Lock 和 RLock 的区别如下:
threading.Lock:它是一个基本的锁对象,每次只能锁定一次,其余的锁请求,需等待锁释放后才能获取。
threading.RLock:它代表可重入锁(Reentrant Lock)。对于可重入锁,在同一个线程中可以对它进行多次锁定,也可以多次释放。如果使用 RLock,那么 acquire() 和 release() 方法必须成对出现。如果调用了 n 次 acquire() 加锁,则必须调用 n 次 release() 才能释放锁。
在实现线程安全的控制中,比较常用的是 RLock。通常使用 RLock 的代码格式如下:使用 RLock 对象来控制线程安全,当加锁和释放锁出现在不同的作用范围内时,通常建议使用 finally 块来确保在必要时释放锁。