python3 GIL锁/互斥锁Lock和递归锁Rlock
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释放锁