zoukankan      html  css  js  c++  java
  • 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释放锁
     
  • 相关阅读:
    C#listbox使用方法
    poj 3894 System Engineer (二分图最大匹配--匈牙利算法)
    Java实现 蓝桥杯VIP 算法训练 连接字符串
    Java实现 蓝桥杯VIP 算法训练 连接字符串
    Java实现 蓝桥杯VIP 算法训练 比较字符串
    Java实现 蓝桥杯VIP 算法训练 比较字符串
    Java实现 蓝桥杯VIP 算法训练 比较字符串
    Java实现 蓝桥杯VIP 算法训练 比较字符串
    Java实现 蓝桥杯VIP 算法训练 比较字符串
    Java实现 蓝桥杯VIP 算法训练 黑白无常
  • 原文地址:https://www.cnblogs.com/lilyxiaoyy/p/11031986.html
Copyright © 2011-2022 走看看