1. 前言
这篇文章重点讲解GIL存在的意义以及问题,同时也说下多线程,多协称以及多进程编程模型中,GIL对于他们的影响,因为参与异步编程的进程,线程和协称都在一定程度上在各自领域发挥作用,如何有效利用内存和CPU才是最关键的,而这就绕不开对GIL的探究,所以这篇文章我们就来了解下GIL对于我们的进程,线程以及协称的影响,欢迎大家关注点赞分享哦。
2. 吃透GIL
本文是以Cpython解释器作为Python解释器讲解。
GIL概念:
GIL是Python中的一个全局解释锁,是Python设计解释器Cpython的一个技术术语,用于在解释器执行Python线程时,锁住当前运行的线程,防止其他线程执行。在这个基础上,你就明白为什么说,Python是单线程的语言了,因为在GIL的限制下,只能同时执行一个线程,所谓的多线程实际上是,线程获取和释放GIL的切换过程,看起来像多线程。
GIL目的:
- 内存管理的race condition资源竞争,线程安全的问题
- C语言库大部分不是原生线程安全的
3. 进程与GIL的关系
一个Python解释器就是一个进程,所以每个进程只带有一个GIL。如下图所示:
可不可能多个Python Process 共享一个Interpreter?
就我目前的认知我觉得不可能。而且如果你是用fork从当前process创建新的process,则是明确的不可能,因为fork你可以理解为是一个deep copy,新创建的process内部是一个实打实的interpreter instance 的clone。这也从另一个方面说明,multi-processing 比 multi-threading的overhead消耗要大。
4. 线程与GIL的关系
只有在同一个process内的threads才有竞争关系,需要抢夺GIL来执行代码;不同process下的threads属于八竿子打不着的关系,更不要说去竞争GIL了。如下图所示:
5. 协称与GIL的关系
其实协称是线程的微缩版,内存开销以及CPU上下文切换开销比线程小而已,再就是它有自己的事件循环调度器,这个事件循环调度器因为GIL的存在只能在一个线程中运行,所以想要高并发的执行请求,调度器必须底层实现多路IO服用模型(selectors模块,之前文章有讲解),这样才能在单线程中实现高并发。
6. 小结
- 在CPU密集型计算中推荐使用多进程模型
因为多进程模型可以利用多核CPU并行计算,而且每个进程拥有一个解释器,每个解释器拥有自己的GIL,它们之间互不影响,高效完成CPU计算工作。
- 在IO密集型操作中推荐使用多线程模型
因为多线程一定会有GIL的约束,但是Cpython在实现中如果遇到IO操作会主动释放GIL以便其他线程获取GIL,所以在高IO场景中比较推荐多线程模型。
- 在高并发编程中推荐使用协称模型
高并发场景中一定是成千上万的请求需要处理,这个时候线程资源的开销是OS无法cover的,所以迫切需要大量的轻量级协称去代替多线程去处理请求。
异步编程要旨就是变同步为异步,你可以去开辟多进程或者多线程异步去处理请求,但是也要考虑各自的使用场景和内存CPU开销,而协称作为异步编程的佼佼者,你只管用就好了,其他的无需担心。