• GIL(全局解释器锁)


    GIL:全局解释器锁,只存在于CPython解释器

    锁是为了避免资源竞争造成数据的错乱
    python程序的执行过程
        1.启动解释器进程 :python.exe
        2.解析你的py文件并执行它
    # 当一个py启动后,会先执行主线程中的代码
    # 在以上代码中又开启了子线程,子线程的任务还是执行代码
    # 解释器在一个进程中只有一个(解释器也是一堆代码)
    # 主线和子线都要去调用解释器的代码,那就产生了竞争关系
    为什么要有GIL:在同一时间只有一个线程在使用解释器
    每个py程序中都必须有解释器参与,解释器其实就是一堆代码
    相当于多个线程要调用同一个解释器代码,共享导致竞争,竞争就要出事,所有给解释器加互斥锁
    
    程序中只有一个线程的时候还需要GIL吗?
    python中内存管理依赖于GC(一段用于回收内存的代码)也需要一个线程 除了你自己开的线程,系统还有一些内置线程,就算你的代码不会去竞争解释器,内置线程也可能会竞争所以必须加上锁
    例如:GC发现变量x引用计数为0,正准备清扫,CPU突然切换到了另一个线程a
    a拿着x进行使用,在使用的过程中,又切换到了GC,GC接着把X指向的空间进行释放
    这样一来a中的x就无法使用了,GIL将分配内存回收内存相关的操作加了锁
    
    
    GIL无法避免自定义的线程中的数据竞争问题
    当一个线程遇到了IO,同时解释器也会自动解锁,去执行其他线程,CPU会切换到其他程序

     GIL性能:

    解释器加锁以后
    加锁虽然保证了数据的安全,但是降低了性能,在多CPU的机器上,无法利用多核提升效率
    其他线程要想执行,必须等到之前的线程释放了GIL,这就意味着:同一时间只有一个线程在运行,效率比较低
    这是一个全球性的问题,你可以尝试解决一下
    代码执行有两种状态: 
    阻塞 遇上i
    /o,失去CPU的执行权(CPU等待IO完成)
    非阻塞 代码正常执行,比如循环一千万次,(CPU占用时间过长)中途CPU可能切换走,又很快会回来(CPU在计算)
    假如有32核CPU要处理一个下载任务,电脑性能很高,但是网络速度慢 100k
    /s,文件大小为1024kb 如果你的代码中IO操作非常多,cpu性能不能直接决定你的任务处理速度
    案例: 目前有三个任务,每个任务处理需一秒,获取源数据需要一小时 3个CPU 需要 一小时1秒 1个cpu 需要 一小时3秒
    在IO密集的程序中:CPU性能无法直接决定程序的执行速度
    在计算密集的程序中:CPU性能可以直接决定程序的执行速度
    效率问题致命吗?
    不是致命
    因为目前很多程序 都是需要网络的 网络速度远比CPU慢 假设你的网络需要10ms python 3ms
    区分IO密集 与 计算密集
    为什么不用其他解释器?
    因为cpython是c语言实现 可以无缝对接c现有的所有库 就是很多现成的功能
    多进程:适用于计算密集型,进程属于资源单位,计算会产生大量数据,便于存储
    多线程:适用于I/O密集型,线程是CPU的执行单位,相当于流水线,线程切换更加迅速

     计算密集测试:

     1 from threading import Thread
     2 from multiprocessing import Process
     3 import time
     4 
     5 
     6 # 计算密集任务
     7 
     8 def task1():
     9     sum = 1
    10     for i in range(10000000):
    11         sum *= i
    12 
    13 
    14 def task2():
    15     sum = 1
    16     for i in range(10000000):
    17         sum *= i
    18 
    19 
    20 def task3():
    21     sum = 1
    22     for i in range(10000000):
    23         sum *= i
    24 
    25 
    26 def task4():
    27     sum = 1
    28     for i in range(10000000):
    29         sum *= i
    30 
    31 
    32 def task5():
    33     sum = 1
    34     for i in range(10000000):
    35         sum *= i
    36 
    37 
    38 def task6():
    39     sum = 1
    40     for i in range(10000000):
    41         sum *= i
    42 
    43 
    44 if __name__ == '__main__':
    45     # 开始时间
    46     st_time = time.time()
    47     # 多线程情况下
    48     # t1 =  Thread(target=task1)
    49     # t2 = Thread(target=task2)
    50     # t3 = Thread(target=task3)
    51     # t4 = Thread(target=task4)
    52     # t5 = Thread(target=task5)
    53     # t6 = Thread(target=task6)
    54 
    55     t1 = Process(target=task1)
    56     t2 = Process(target=task2)
    57     t3 = Process(target=task3)
    58     t4 = Process(target=task4)
    59     t5 = Process(target=task5)
    60     t6 = Process(target=task6)
    61 
    62     t1.start()
    63     t2.start()
    64     t3.start()
    65     t4.start()
    66     t5.start()
    67     t6.start()
    68     #
    69     # t1.join()
    70     # t2.join()
    71     # t3.join()
    72     # t4.join()
    73     # t5.join()
    74     # t6.join()
    75 
    76     print(time.time() - st_time)
    线程和进程在计算密集下性能对比

    I/O密集测试:

     1 from threading import Thread
     2 from multiprocessing import Process
     3 import time
     4 
     5 # I/O密集任务
     6 def task1():
     7     time.sleep(3)
     8 
     9 
    10 def task2():
    11     time.sleep(3)
    12 
    13 
    14 def task3():
    15     time.sleep(3)
    16 
    17 
    18 def task4():
    19     time.sleep(3)
    20 
    21 
    22 def task5():
    23     time.sleep(3)
    24 
    25 
    26 def task6():
    27     time.sleep(3)
    28 
    29 if __name__ == '__main__':
    30 
    31     # 开始时间
    32     st_time = time.time()
    33     # 多线程情况下
    34     # t1 = Thread(target=task1)
    35     # t2 = Thread(target=task2)
    36     # t3 = Thread(target=task3)
    37     # t4 = Thread(target=task4)
    38     # t5 = Thread(target=task5)
    39     # t6 = Thread(target=task6)
    40 
    41 
    42     t1 = Process(target=task1)
    43     t2 = Process(target=task2)
    44     t3 = Process(target=task3)
    45     t4 = Process(target=task4)
    46     t5 = Process(target=task5)
    47     t6 = Process(target=task6)
    48 
    49     t1.start()
    50     t2.start()
    51     t3.start()
    52     t4.start()
    53     t5.start()
    54     t6.start()
    55 
    56     # t1.join()
    57     # t2.join()
    58     # t3.join()
    59     # t4.join()
    60     # t5.join()
    61     # t6.join()
    62 
    63     print(time.time() - st_time)
    线程和进程在I/O密集下性能对比

    与自定义互斥锁的异同:

    相同点:都是互斥锁  争抢执行权是无序的  执行被锁定的代码时有序的
    不同点:GIL锁的是解释器的数据 自定义互斥锁锁得是用户自定义的数据
    GIL的加锁与解锁 是自动执行的
    自动释放的时间点: io/代码执行完毕 和 同一线程执行时间过长3ms(py3中)
    执行的字节码指令数量达到一定值(py2中)
    代码:
     1 from threading import Thread, Lock
     2 import time
     3 
     4 mutex = Lock()
     5 num = 1
     6 
     7 def task():
     8     global num
     9     mutex.acquire()# 第二个线程被互斥锁阻塞,等待线程一执行结束
    10     temp = num
    11     # print(temp)
    12     time.sleep(1)  # 当你们线程中出现io时,GIL锁就解开,去执行第二个线程
    13     num = temp + 1
    14     mutex.release()  # 线程任务结束时GIL锁解开
    15 
    16 t1 = Thread(target=task, )
    17 
    18 t2 = Thread(target=task, )
    19 t1.start()
    20 t2.start()
    21 t1.join()
    22 t2.join()
    23 print(num) # 执行结果为3 
  • 相关阅读:
    顺序栈的初始化,建立,插入,查找,删除。
    循环单链表的初始化,建立,插入,查找,删除。
    双链表的初始化,建立,插入,查找,删除。
    CSS轮廓
    CSS框模型
    CSS字体
    CSS层叠样式表的分类:
    CSS 背景
    利用visio2003进行数据库的反向工程
    CSS 选择器分类
  • 原文地址:https://www.cnblogs.com/xuechengeng/p/9947795.html
Copyright © 2020-2023  润新知