理解python GIL 全局锁

本文深入探讨了Python中的全局解释器锁机制,解释了其如何限制多线程并发执行,导致性能瓶颈。重点分析了线程切换机制,包括I/O操作和CPU密集型任务下的锁释放机制,以及这种机制如何优化多线程执行效率。通过实例和原理阐述,旨在帮助开发者理解Python多线程性能受限的原因及优化策略。

众所周知,python中有全局解释器锁,由于全局解释器锁的存在,所以在同一时间内,python解释器只能运行一个线程的代码,这大大影响了python多线程的性能。

在python,使用的都是操作系统级别的线程,因此在linux中 python使用的是pthread 在windows下也是使用的Windows的原生线程来实现。

python GIL 之所以会影响多线程等性能,是应为在多线程的情况下,只有当线程获得了一个全局锁的时候,那么该线程的代码才能运行,而全局锁只有一个,所以使用python多线程,在同一时刻也只有一个线程在运行,因此在即使在多核的情况下也只能发挥出单核的性能。

既然python在同一时刻下只能运行一个线程的代码,那线程之间是如何调度的呢?
对于有io操作的线程,当一个线程在做io操作的时候,因为io操作不需要cpu,所以,这个时候,python会释放python全局锁,这样其他需要运行的线程就会使用该锁。
对于cpu密集型的线程,比如一个线程可能一直需要使用cpu做计算,那么python中会有一个执行指令的计数器,当一个线程执行了一定数量的指令时,该线程就会停止执行并让出当前的锁,这样其他的线程就可以执行代码了。
由上面可知,至少有两种情况python会做线程切换,一是一但有IO操作时,会有线程切换,二是当一个线程连续执行了一定数量的指令时,会出现线程切换。当然此处的线程切换不一定就一定会切换到其他线程执行,因为如果当前线程 优先级比较高的话,可能在让出锁以后,又继续获得锁,并优先执行。

linux下 python使用的是 pthread 和 有一个互斥量和一个 条件变量来实现全局锁功能。

下面是参考文档的下载地址
该文档由python cookbook的作者编写,有很高的参考价值
http://download.csdn.net/detail/tuxl_c_s_d_n/8677825
### GIL的工作原理 全局解释器锁(GIL)是CPython解释器的核心线程同步机制,其本质是一个互斥锁(Mutex)。该机制强制规定:同一时刻只允许一个线程执行Python字节码。这种设计确保了引用计数的原子性操作、内存分配的安全性和垃圾回收的正确性。GIL的设计初衷是为了简化内存管理,通过单线程原子操作避免竞争,同时保证C扩展的线程安全,并减少锁的数量和复杂度[^4]。 在多线程环境中,GIL的存在意味着即使有多个CPU核心可用,Python中的多线程程序也无法实现真正的并行计算。每个线程在执行Python字节码时必须获得GIL,而其他线程则必须等待当前线程释放GIL后才能继续执行。这种情况对于I/O密集型任务影响较小,因为线程在进行I/O操作时会主动释放GIL,从而允许其他线程运行。但对于CPU密集型任务,由于线程几乎不会主动释放GIL,因此会导致严重的性能瓶颈[^1]。 ### GIL对多线程程序的影响 GIL的存在对Python的多线程性能有着深远的影响。特别是在多核处理器上,GIL限制了Python程序的并发性能。尽管可以创建多个线程来处理不同的任务,但由于GIL的存在,这些线程实际上是在同一个CPU核心上串行执行的。这使得多线程程序在CPU密集型任务中无法充分利用多核处理器的优势,从而导致性能下降[^2]。 然而,对于I/O密集型任务,GIL的影响相对较小。在这种情况下,线程会在等待I/O操作完成时主动释放GIL,从而使其他线程有机会运行。这意味着,在处理大量I/O操作的应用中,如网络服务器或文件处理程序,GIL的影响可以被有效缓解[^5]。 ### 解决方案 为了规避或减轻GIL的限制,提高Python程序的并发性能,可以采用以下几种方法: - **多进程**:使用`multiprocessing`模块创建多个进程,每个进程都有独立的GIL,从而实现真正的并行计算。 ```python from multiprocessing import Process def worker(): print('Worker process') if __name__ == '__main__': processes = [] for _ in range(5): p = Process(target=worker) processes.append(p) p.start() for p in processes: p.join() ``` - **C扩展**:编写C语言编写的扩展模块,可以在这些模块中释放GIL,从而允许其他线程同时运行。 - **异步编程**:使用`asyncio`库进行异步编程,利用事件循环和协程实现高效的并发模型。 ```python import asyncio async def worker(): print('Worker coroutine') if __name__ == '__main__': loop = asyncio.get_event_loop() tasks = [worker() for _ in range(5)] loop.run_until_complete(asyncio.gather(*tasks)) loop.close() ``` - **线程池**:使用`concurrent.futures.ThreadPoolExecutor`来管理线程池,适用于I/O密集型任务。 ```python from concurrent.futures import ThreadPoolExecutor def worker(): print('Worker thread') if __name__ == '__main__': with ThreadPoolExecutor(max_workers=5) as executor: futures = [executor.submit(worker) for _ in range(5)] ``` 通过上述方法,可以在一定程度上规避或减轻GIL的限制,提高Python程序的并发性能。然而,需要注意的是,这些方法各有优缺点,选择合适的方法取决于具体的应用场景和需求[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值