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释放锁
 
原文地址:https://www.cnblogs.com/lilyxiaoyy/p/11031986.html