zoukankan      html  css  js  c++  java
  • 并发编程之GIL锁

    并发编程之GIL锁

    1.定义

    ​ GIL(Global_Interpreter_Lock)全局解释器锁:

    ​ 在cpython中,GIL是一个互斥锁,为了防止多个本地线程在同一时间执行python字节码,因为cpython中的内存管理是非线程安全的,而cpython中的很多特性都依赖于这个特性.

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

    1. python程序本质就是一堆字符串,所以运行一个python程序时 必须要开启开启一个解释器

    2. 但是在一个python程序中解释器只有一个 所有代码都要交给它来解释执行

    3. 当有多个线程都要执行代码时就会产生线程安全问题

    3.cpython解释器与GC(垃圾回收线程)的问题

    python会自动帮我们处理垃圾 清扫垃圾也是一对代码 也需要开启一个线程来执行

    也就是说就算程序没有自己开启线程 内部也有多个线程

    GC线程与我们程序中的线程就会产生安全问题

    例如: 线程1 要定义一个变量a=10

    步骤:1.申请内存空间,

    ​ 2.数据存入空间(变量值的引用计数为0)

    ​ 若此时,CPU切换到GC进程,将会出发垃圾回收机制

    ​ 3.引用计数+1

    4.带来的问题

    ​ GIL是一把互斥锁,降低效率:具体表现是 在CPython 即便开启了多线程 而且CPU也是多核的 却无法并行执行任务;因为解释器只有一个 同一时间只能有一个任务在执行 .

    5.如何解决

    无彻底办法解决,只能尽可能的避免GIL锁影响我们的效率

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

    2.对任务进行区分

    ​ 任务可以分为两类

    ​ 1.计算密集型 基本没有IO 大部分时间都在计算 例如人脸识别 图像处理

    ​ 由于多线程不能并行 应该使用多进程 将任务分给不同CPU核心

    ​ 2.IO密集型 计算任务非常少,大部分时间都在等待IO操作

    ​ 由于网络IO速度对比CPU处理速度非常慢, 多线程并不会造成太大的影响

    ​ 另外如有大量客户端连接服务 进程根本开不起来 只能用多线程

    6.关于性能的讨论

    ​ 之所以加锁是为了解决线程安全问题

    ​ 由于有了锁 导致Cpython中多线程不能并行只能并发

    ​ 但是我们不能因此否认python

    ​ 1.python是一门语言 ,GIL是Cpython解释器的问题

    ​ 2.如果是单核CPU ,GIL不会造成任何影响

    ​ 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()
    
        ps = []
        for i in range(5):
            # p = Process(target=task)    #耗时:9.214441299438477
            # p =Thread(target=task)       #耗时:16.144373178482056
            p.start()
            ps.append(p)
    
        for i in ps:i.join()
    
        #计时
        print(time.time()-start)
        
        
    # 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)
    
    # 多线程胜于多进程    
     
    

    7.GIL于自定义锁的区别

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

    自定义锁,锁的是解释器以外的共享资源 例如:硬盘上的文件 控制台

    对于这种不属于解释器的数据资源就应该自己加锁处理

  • 相关阅读:
    Vue-router2.0学习笔记(转)
    vue-cli 搭建项目
    打开一个vue项目
    Webpack,Browserify和Gulp三者之间到底是怎样的关系
    读取ByteBuffer有效的数据
    node-sass 安装失败的解决措施[转]
    SpringCloud2.0
    Docker
    分布式文件系统之FastDFS
    SVN的使用
  • 原文地址:https://www.cnblogs.com/bruce123/p/11184421.html
Copyright © 2011-2022 走看看