GIL
GIL:global interpreter lock(cpython)
在python中,一个线程对应于c中的一个线程。
gil使得同一个时刻只有一个线程在CPU上执行字节码(python在执行的时候会将py文件编译成字节码)。
同时也预示着无法将多个线程映射到多个CPU上运行,无法体现多CPU的优势。
只要运行一个python进程,里面不管有多少个线程,他都只能运行在一个CPU上。
在其它静态语言里面可以将多个线程映射到多个CPU上。
因此,在python里面,并发就非常受限,python一直在努力的去GIL化。
但是短期内是无法实现的,因为大量的第三方包都是使用cpython来完成的。
当然也有其它的解释器,比如pypi去GIL化。
GIL锁为了线程运行安全,因为多个线程运行,尤其是运行同一段代码的时候,十分容易出错。
所以python在最初的时候就加了一把GIL锁,这使得同一时刻只有一个线程在CPU上执行字节码。
这样保证了某种程度上线程是安全的。python正是由于GIL锁使得多线程的效率不是很高。
虽然同一时刻只有一个线程运行在CPU上,那么是否就意味着编写多线程编码就是安全的了?
就不去考虑线程间的同步了?实际上不是的。
通过下面示例可以知道,GIL锁会在适当的时间释放掉,不会一直占有。
from threading import Thread from multiprocessing import Process a = 0 def add(): global a b = 0 for i in range(1000000): a += 1 b += 1 print("循环次数:",b) def desc(): global a c = 0 for i in range(1000000): a -= 1 c += 1 print("循环次数:",c) def task(): t1 = Thread(target=add) t2 = Thread(target=desc) t1.start() t2.start() t1.join() t2.join() print(a) if __name__ == "__main__": for i in range(4): p = Process(target=task) p.start() p.join()
如果按照代码的逻辑,那么最终打印的结果都为0。
执行结果:
循环次数: 1000000
循环次数: 1000000
-4652
循环次数: 1000000
循环次数: 1000000
468960
循环次数: 1000000
循环次数: 1000000
-61354
循环次数: 1000000
循环次数: 1000000
196468
我们发现每次的执行结果都不相同,
原因可能有二:
第一,两个任务没有做完,
第二,两个任务之间的变量相互影响,也就是GIL锁在途中被释放掉了。
我们通过打印循环次数说明任务都做完了,那么就只能是GIL锁在任务执行过程中被释放掉了,导致两个任务的a变量相互影响。
当把GIL这把锁交给一个线程之后,他不会等到线程执行完毕之后再释放。
它会根据字节码执行的行数以及时间片,然后把它释放出来。
另外,当GIL遇到IO操作的时候也会释放。也正是由于这个原因,GIL在IO操作频繁的时候非常适用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理