并发编程之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锁住的是解释器级别的数据

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

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

上一篇:第五十五篇 死锁、GIL锁以及Pool


下一篇:Archive: ****** End-of-central-directory signature not found. Either this file is not a zipfil