并发编程之GIL锁
1.定义
GIL(Global_Interpreter_Lock)全局解释器锁:
在cpython中,GIL是一个互斥锁,为了防止多个本地线程在同一时间执行python字节码,因为cpython中的内存管理是非线程安全的,而cpython中的很多特性都依赖于这个特性.
2.cpython解释器与python程序之间的关系
-
python程序本质就是一堆字符串,所以运行一个python程序时 必须要开启开启一个解释器
-
但是在一个python程序中解释器只有一个 所有代码都要交给它来解释执行
-
当有多个线程都要执行代码时就会产生线程安全问题
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锁住的是解释器级别的数据
自定义锁,锁的是解释器以外的共享资源 例如:硬盘上的文件 控制台
对于这种不属于解释器的数据资源就应该自己加锁处理