• 死锁现象,递归所,信号量,GIL


    各式各样的锁

    死锁现象

    • 死锁指的是某个资源被占用后一直得不到释放,导致其他需要这个资源的线程进入阻塞状态
    • 产生死锁的情况:
      • 第一种:对同一把互斥锁,加锁了多次
        • 这么做没有意义,是因为忘了之前上锁了
        • 可以给acquire加上超时参数,能够保证线程不被卡死
      • 第二种:一个共享资源有多把锁,被不同的进程或是线程所持有,导致双方互相等待对方释放,从而卡死程序
        • 抢锁一定要按照相同的顺序去抢:都抢筷子或者都抢碗
        • 加上超时参数

    递归锁

    • 与普通锁的区别:

      • 多线程之间都有互斥的效果

      • 不同在于,同一个线程可以对这个锁执行多次acquire,那就是锁多次,需要用同等次数的release 才可以解开

    信号量

    • 可以限制同时并发执行公共代码的线程数量
    • 如果限制数量为1,则与普通互斥锁没有区别
    • 不是用来解决安全问题的,而是用来限制并发峰值的,但是没什么用,因为这是开了线程只是不让执行,而不是没开线程
    from threading import Semaphore,currentThread,Thread
    import time
    
    s = Semaphore(3)	# 有三把锁
    
    def task():
        s.acquire()
        time.sleep(1)
        print(currentThread().name)
        s.release()
    
    for i in range(6):
        Thread(target=task).start()
    
    Thread-1
    Thread-3
    Thread-2
    Thread-4
    Thread-5
    Thread-6
    

    虽然可以三个三个的输出,但是顺序无法控制

    GIL

    什么是GIL锁?

    '''
    In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple 
    native threads from executing Python bytecodes at once. This lock is necessary mainly 
    because CPython’s memory management is not thread-safe. (However, since the GIL 
    exists, other features have grown to depend on the guarantees that it enforces.)
    '''
    
    在cpython 中 这个全局解释器锁 或者称为GIL是一个互斥锁 ,是为了阻止多个本地线程在同一时间执行python字节码
    因为cpython的内存管理是非线程安全的,这个锁是非常必要的  因为其他越来越多的特性依赖这个特性   
    

    为什么需要这把锁

    • cpython解释器与python程序之间的关系

    Python程序本质就是一堆字符串,所以运行一个Python程序时,必须要开启一个解释器,但是一个Python程序中解释器只有一个,所有代码都要交给它来解释执行。

    • 当有多个线程都要执行代码时就会产生线程安全问题。
    那我们不开启子线程是不是就没有问题了? 不是的,Cpython解释器会有一个GC(垃圾回收)线程
    
    Python会自动帮我们处理垃圾,清扫垃圾也是一堆代码,也需要开启一个线程来执行
    
    也就是说,就算程序没有自行开启线程,内部也有多个线程,只是Python帮我们封装了
    
    而GC线程与我们程序中的线程就会产生安全问题
    
    例如: 线程A要定义一个变量
    
    步骤: 先申请一块空的内存,再把数据装进去,最后引用计数加1,
    	
    **但是如果当你进行到第二步的时候,CPU切换到了GC线程,GC就会把这个值当成垃圾清理**
    

    带来的问题

    GIL是一把互斥锁,就会导致效率降低

    具体表现是,在CPython中,即便开启了多线程,而且CPU也是多核的,但是依旧无法并行执行任务

    因为解释器只有一个,同一时间只能有一个任务在执行

    如何解决

    没办法解决,因为有一部分历史遗留问题,只能尽可能的避免GIL锁带来的影响

    1. 使用多进程能够实现并行,从而更好的利用多核CPU

    2. 对任务进行区分

    这类任务又可以分为两类
    	1. 计算密集型:基本没有IO,大部分时间都在计算。例如:人脸识别,图像处理
            1.1. 由于多线程不能并行,应该使用多进程,将任务分给不同的CPU核心
               		
    	2. IO密集型:基本没有计算,大部分时间都在IO操作
    		2.1. 虽然并发执行慢,但是由于网络IO速度相对于CPU的处理速度来说非常慢,多线程并不会造成太大的效率影响
    		2.2. 另外如果有大量的客户端连接服务器,进程根本开不起来,只能使用多线程。
    
    以做饭洗衣为例
    

    关于性能的讨论

    之所以加锁是为了解决线程安全问题
    
    由于有了锁,导致Cpython中多线程不能并行只能并发
    但是我们不能够因此否认Python
    1. Python是一门语言,而GIL是CPython解释器的问题,还有JPython解释器,PyPy解释器
    2,如果是单核CPU,就不会造成任何影响
    3. 由于目前的大多数序都是基于网络的,网络速度对比CPU是非常慢的, 导致即使多核CPU也无法提高效率。
    4. 对于IO密集型任务,不会有太大的影响  
    5.如果没有这把锁,我们程序猿将必须自己来解决安全问题。 
    
    • 性能测试
    from multiprocessing import Process
    from threading import  Thread
    import time
    
    # # 计算密集型任务
    # def task():
    #     for i in range(100000000):
    #         1+1
    
    # if __name__ == '__main__':
    #     start_time = time.time()
    
    #     ps = []
    #     for i in range(5):
    #         p = Process(target=task)	# 进程测试
    #         # p = Thread(target=task)	# 线程测试
    #         p.start()
    #         ps.append(p)
    #
    #     for i in ps:i.join()
    #
    #     print("共耗时:",time.time()-start_time)
    
    # 量小时多线程胜,量大时多进程胜,总体多线程胜,因为计算量不会小
    
    
    # IO密集型任务
    def task():
        for i in range(100):
            with open(r"1.死锁现象.py",encoding="utf-8") as f:
                f.read()
    
    if __name__ == '__main__':
        start_time = time.time()
    
        ps = []
        for i in range(10):
            p = Process(target=task)
            # p = Thread(target=task)
            p.start()
            ps.append(p)
    
        for i in ps:i.join()
        print("共耗时:",time.time()-start_time)
    
    # 多线程胜
    

    GIL与自定义锁的区别

    GIL锁住的是解释器级别的数据,而自定义锁锁的是解释器以外的共享资源,例如:硬盘上的文件,控制台

    代码是为了模拟,强行加了锁,##GIL锁在遇到阻塞时会释放,lock锁不会##

    虽然没有在代码中有实际作用,但是理解这个有助于更高效率处理问题

  • 相关阅读:
    hdu1874 畅通project续 最短路 floyd或dijkstra或spfa
    基于Linux环境Tomcat-MySQL的server搭建
    C++中 pair 的使用方法
    UI 经常用法总结之--- UIWindow UIView (不断更新中)
    LeetCode题解 || Longest Substring Without Repeating Characters (O(n)算法)问题
    HDU 1874 畅通project续 (最短路径)
    android studio 导入第三方库的记录
    android创建桌面快捷键shortcut
    Eclipse:Cannot complete the install because of a conflicting dependency.问题解决
    js保留两位小数的解决的方法
  • 原文地址:https://www.cnblogs.com/lucky75/p/11140598.html
Copyright © 2020-2023  润新知