本帖最后由 Jahanxu 于 2019-4-20 13:38 编辑
GIL是什么
GIL百度解释:全局解释器锁(Global Interpreter Lock)是计算机程序设计语言解释器用于同步线程的工具,使得在同一进程内任何时刻仅有一个线程在执行。常见例子有CPython(JPython不使用GIL)与 Ruby MRI (也称作 CRuby,Ruby语言解释器)
我们在开发一个大型的应用程序时,为了提高程序的执行效率。让程序能最优的利用电脑的资源,往往会用多进程或者多线程的方式来实现。但是多进程和多线程在使用时也各有优缺点,以下是两者对比:
关系对比:
- 线程依附进程,有进程才有线程
- 一个进程至少有一个线程,也可以开辟多个线程
区别对比:
- 线程可以共享全局变量,主要资源竞争问题,**解决办法**:互斥锁和线程同步
- 进程不可以共享全局变量, 进程比线程更稳定, 进程资源开销大于线程
- 进程是**操作系统资源分配的基本单位**,线程是**CPU调度的基本单位**
- 线程不能独立存在,必须依附于进程
优缺点对比:
- 进程:
- 优点:稳定性高,可以使用多核资源
- 缺点:资源开销大
- 线程:
- 优点:资源开销小
- 缺点:不能使用多核资源,稳定性低于进程
根据上面的对比可以知道只有多线程才会存在GIL的问题,这个问题产生的核心原因就是:资源共享
进程和线程选择
我们在设计一个程序的时候什么时候设计成多进程模式,什么时候设计成多线程模式,那我们就要知道多线程其实因为GIL的原因导致了同一时间只有一个线程能被CPU调度。只是由于时间是毫秒级的,给我们的表象就好像同一时间多个线程都在运行。
那这两种模式怎么选择呢,下面介绍一下两个概念:
计算密集型:每个请求的命令中,大都包含不同的参数值,很难重用前一次计算的结果,所以要按照约定的业务逻辑重新计算,并按照约定的格式返回数据,且计算在总耗时中占比较大。
IO密集型:指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。
通过比较知道计算密集型需要很高的CPU占用率,一直进行计算操作;而IO密集型则把大量的时间花在了输入输出上面,而数据的从发送到接收会有一段时间(对于我们来说很短),就好比我发送一个数据从发送出去到接收耗时5s,我需要发送三次,若用单线程则需要15s;假如使用多线程,在第一次发出去之后,接着发第二次,再接着发第三次,因为返回数据需要时间所以为了不让第一个线程在等待状态浪费CPU资源,CPU释放掉第一次的发送,调第二次的发送线程,第三次同理。
总结:
计算密集型:用进程设计
IO密集型:用线程或者Python特有的协程
再回过头来说GIL的问题,由于GIL是历史遗留问题,在CPython(C语言写的Python解释器)中难以移除,那为了提高CPU的利用率不想使用GIL,有两种办法:
1、更换Python解释器
PyPy:PyPy是另一个Python解释器,它的目标是执行速度,PyPy采用JIT技术,对Python代码进行动态编译,所以可以显著提高Python代码的执行速度。
Jython:Jython是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行。
2、核心代码更换其他语言实现
用到多线程的地方可以用其他代码来实现,作为Python的链接库,这就是Python语言的强大之处。
|
|