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 
posted @ 2018-11-12 17:25  ChuckXue  阅读(1416)  评论(0编辑  收藏  举报