GIL锁(Global Interpreter Lock)全局解释器锁
在Cpython解释器中,同一进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势.
那么,我们改如何解决GIL锁的问题呢?
1.更换cpython为jpython(不建议)
2.使用多进程完成多线程的任务
3.在使用多线程可以使用c语言去实现
问题1: 什么时候会释放GIL锁?
1 遇到像 I/O操作这种 会有时间空闲情况 造成cpu闲置的情况会释放GIL
2 会有一个专门ticks进行计数 一旦ticks数值达到100 这个时候释放GIL锁 线程之间开始竞争GIL锁(说明:ticks这个数值可以进行设置来延长或者缩减获得Gil锁的线程使用cpu的时间)
问题2: 互斥锁和GIL锁的关系?
GIL锁 : 保证同一时刻只有一个线程能使用到cpu
互斥锁 : 多线程时,保证修改共享数据时有序的修改,不会产生数据修改混乱
首先假设只有一个进程,这个进程中有两个线程 Thread1,Thread2, 要修改共享的数据date, 并且有互斥锁
执行以下步骤
(1)多线程运行,假设Thread1获得GIL可以使用cpu,这时Thread1获得 互斥锁lock,Thread1可以改date数据(但并没有开始修改数据)
(2)Thread1线程在修改date数据前发生了 I/O操作 或者 ticks计数满100 (注意就是没有运行到修改data数据),这个时候 Thread1 让出了GIL,GIL锁可以被竞争
(3) Thread1 和 Thread2 开始竞争 GIL (注意:如果Thread1是因为 I/O 阻塞 让出的GIL Thread2必定拿到GIL,如果Thread1是因为ticks计数满100让出GIL 这个时候 Thread1 和 Thread2 公平竞争)
(4)假设 Thread2正好获得了GIL, 运行代码去修改共享数据date,由于Thread1有互斥锁lock,所以Thread2无法更改共享数据date,这时Thread2让出GIL锁 , GIL锁再次发生竞争
(5)假设Thread1又抢到GIL,由于其有互斥锁Lock所以其可以继续修改共享数据data,当Thread1修改完数据释放互斥锁lock,Thread2在获得GIL与lock后才可对data进行修改
以上描述了 互斥锁和GIL锁的 一个关系.
# -*- coding: utf-8 -*- import time from threading import Thread, Lock n = 10 def func(): with mutex: global n temp = n time.sleep(0.5) n = temp - 1 if __name__ == '__main__': '''线程之间数据是共享的,加锁来保护为了保护共享的数据,缺点线程变成了串行''' mutex = Lock() # 线程不需要传递这把锁,子线程可以直接使用 t_l = [] for i in range(10): t = Thread(target=func) t_l.append(t) t.start() [tt.join() for tt in t_l] print(n) # 0
# -*- coding: utf-8 -*- import threading from threading import Thread, Lock def func(): lockA.acquire() print("%s拿到A锁" % threading.current_thread().getName()) lockB.acquire() print("%s拿到B锁" % threading.current_thread().getName()) lockB.release() print("%s释放B锁" % threading.current_thread().getName()) lockA.release() print("%s释放A锁" % threading.current_thread().getName()) lockB.acquire() print("%s拿到B锁" % threading.current_thread().getName()) lockA.acquire() print("%s拿到A锁" % threading.current_thread().getName()) lockA.release() print("%s释放A锁" % threading.current_thread().getName()) lockB.release() print("%s释放B锁" % threading.current_thread().getName()) if __name__ == '__main__': '''死锁现象,在同一进程的多个线程,一个线程所需要的锁,被另外一个线程抢到了''' lockA = Lock() lockB = Lock() for i in range(10): t = Thread(target=func) t.start() # Thread-1拿到A锁 # Thread-1拿到B锁 # Thread-1释放B锁 # Thread-1释放A锁 # Thread-2拿到A锁 # Thread-1拿到B锁
# -*- coding: utf-8 -*- import threading from threading import Thread, RLock def func(): mutex.acquire() print("%s拿到锁" % threading.current_thread().getName()) mutex.acquire() print("%s拿到锁" % threading.current_thread().getName()) mutex.release() print("%s释放锁" % threading.current_thread().getName()) mutex.release() print("%s释放锁" % threading.current_thread().getName()) mutex.acquire() print("%s拿到锁" % threading.current_thread().getName()) mutex.acquire() print("%s拿到锁" % threading.current_thread().getName()) mutex.release() print("%s释放锁" % threading.current_thread().getName()) mutex.release() print("%s释放锁" % threading.current_thread().getName()) if __name__ == '__main__': '''递归锁,是计数机制,acquire一次计数加一,release一次计数减一,只有计数为0的时候,线程间才是再次抢锁''' mutex = RLock() for i in range(10): t = Thread(target=func) t.start() # Thread-1拿到锁 # Thread-1拿到锁 # Thread-1释放锁 # Thread-1释放锁 # Thread-2拿到锁 # Thread-2拿到锁 # Thread-2释放锁 # Thread-2释放锁 # Thread-1拿到锁 # Thread-1拿到锁 # Thread-1释放锁 # Thread-1释放锁 # Thread-2拿到锁 # Thread-2拿到锁 # Thread-2释放锁 # Thread-2释放锁 # Thread-3拿到锁 # Thread-3拿到锁 # Thread-3释放锁 # Thread-3释放锁 # Thread-4拿到锁 # Thread-4拿到锁 # Thread-4释放锁 # Thread-4释放锁 # Thread-5拿到锁 # Thread-5拿到锁 # Thread-5释放锁 # Thread-5释放锁 # Thread-3拿到锁 # Thread-3拿到锁 # Thread-3释放锁 # Thread-3释放锁 # Thread-6拿到锁 # Thread-6拿到锁 # Thread-6释放锁 # Thread-6释放锁 # Thread-4拿到锁 # Thread-4拿到锁 # Thread-4释放锁 # Thread-4释放锁 # Thread-7拿到锁 # Thread-7拿到锁 # Thread-7释放锁 # Thread-7释放锁 # Thread-5拿到锁 # Thread-5拿到锁 # Thread-5释放锁 # Thread-5释放锁 # Thread-8拿到锁 # Thread-8拿到锁 # Thread-8释放锁 # Thread-8释放锁 # Thread-9拿到锁 # Thread-9拿到锁 # Thread-9释放锁 # Thread-9释放锁 # Thread-6拿到锁 # Thread-6拿到锁 # Thread-6释放锁 # Thread-6释放锁 # Thread-10拿到锁 # Thread-10拿到锁 # Thread-10释放锁 # Thread-10释放锁 # Thread-7拿到锁 # Thread-7拿到锁 # Thread-7释放锁 # Thread-7释放锁 # Thread-8拿到锁 # Thread-8拿到锁 # Thread-8释放锁 # Thread-8释放锁 # Thread-9拿到锁 # Thread-9拿到锁 # Thread-9释放锁 # Thread-9释放锁 # Thread-10拿到锁 # Thread-10拿到锁 # Thread-10释放锁 # Thread-10释放锁