• 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释放锁
     
  • 相关阅读:
    内核态内存映射
    FS 数据结构
    内存页分配/释放
    用户态内存映射
    WindowsServer 2008 TIME_WAIT
    OutOfMemoryError:修改tomcat启动参数
    windows下Tomcat添加jmx监控
    mysql 5.7.11 安装运行
    mysql 数据库备份与还原
    Win7下虚拟WiFi设置
  • 原文地址:https://www.cnblogs.com/lilyxiaoyy/p/11031986.html
Copyright © 2020-2023  润新知