zoukankan      html  css  js  c++  java
  • day32-4 GIL全局解释锁

    GIL 全局解释器锁

    GIL介绍

    python程序本质就是一堆字符串,所以运行一个python程序时,必须要开启一个解释器。但是在一个python程序中解释器只有一个,所有代码都要交给它来解释执行,当有多个线程都要执行代码时就会产生线程安全问题。

    如python会帮我们进行内存管理,管理也是要写一堆代码,也需要开启一个线程(GC线程)来执行。那就是说就算程序没有自己开启线程,放入解释器执行时也会有多个线程,造成线程安全问题

    GIL本质就是一把互斥锁,将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。所以为解释器加GIL锁,这样在Cpython解释器中,同一个进程下开启的多线程,同一时刻也只能有一个线程执行,无法利用多核优势

    GIL对多线程的影响与使用

    因此只能尽可能避免GIL锁影响程序的效率

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

    2.对任务进行分类

    • 计算密集型:基本上没有IO操作,大部分时间都在计算,例如人脸识别、图像处理。由于多线程不能并行,应该使用多进程将任务分给不同CPU核心
    • IO密集型:计算任务非常少,大部分时间都在等待IO操作。由于网络IO速度对比CPU处理速度非常慢,多线程不会造成太大的影响,另外如有大量客户端连接服务,进程根本开不起来,只能用多线程

    GIL与自定义锁的区别

    GIL锁住的是解释器级别的数据

    自定义锁锁的是解释器以外的共享资源,例如:硬盘上的文件应该自己加锁处理

    from threading import Thread,Lock
    import time
    
    lock = Lock()
    a = 0
    def task():
        global a
        lock.acquire()
        temp = a
        time.sleep(0.01)
        a = temp + 1
        lock.release()
    
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(a)
    

    过程分析:

    1.线程1获得CPU执行权,并获取GIL锁执行代码 ,得到a的值为0后进入睡眠,释放CPU并释放GIL,不释放lock

    2.线程2获得CPU执行权,并获取GIL锁,尝试获取lock失败,无法执行,释放CPU并释放GIL

    3.线程1睡醒后获得CPU执行权,并获取GIL继续执行代码 ,将temp的值0+1后赋给a,执行完毕释放CPU释放GIL,释放lock,此时a的值为1

    4.线程2获得CPU执行权,获取GIL锁,尝试获取lock成功,执行代码,得到a的值为1后进入睡眠,释放CPU并释放GIL,不释放lock

    5.线程2睡醒后获得CPU执行权,获取GIL继续执行代码 ,将temp的值1+1后赋给a,执行完毕释放CPU释放GIL,释放lock,此时a的值为2

  • 相关阅读:
    flask-bootstrap
    SSH
    Spring ContextLoaderListener与DispatcherServlet所加载的applicationContext的区别
    加载spring 的方法。
    简约的form表单校验插件
    javascript 大数值数据运算
    【解题报告】 Task
    【解题报告】 POJ1050 To the Max
    。。。
    【解题报告】 POJ2054 给树染色
  • 原文地址:https://www.cnblogs.com/863652104kai/p/11146924.html
Copyright © 2011-2022 走看看