当前位置: 首页 > 科技观察

我的天啊!Python多线程其实是骗人的?

时间:2023-03-19 14:36:29 科技观察

Python讲解执行原理我是Python线程,我的工作是讲解和执行程序员写的Python代码。之所以解释执行,是因为Python是高级语言,CPU小伙不懂Python代码,需要运行的时候动态翻译成CPU指令。我把Python源代码一个一个“编译”成字节码文件:.pyc,这是一个人类看不懂,只有我看得懂的二进制文件。那么我的工作就简单了,我不断的取出字节码文件中的“指令”进行解释和执行,直到指令全部执行完毕,我就可以休息了。GIL后来,多线程编程技术流行起来,进程中不止我一个线程,又来了几个新的小伙伴。本以为我们可以和平共处,没想到却惹来了麻烦。我们都我行我素,经常导致内存空间出问题,也找不到责任人。终于有一天,我实在受不了了,召集大家商量解决办法。“小朋友们,我们不能再这样各自为政了,我们是一个Team,需要相互配合,一根线可以走得快,一群线在一起才能走得更远!”“老大,你有什么?”说出你的想法,”另一个线程说。“怎么样,让我们??加一把锁吧!它简单快捷。每个线程要执行代码都需要申请这个锁。只有拿到了申请才能执行,否则就得等,”我说。至于保证别人有机会执行吗?”“那怎么算?每执行一个字节码你算一次吗?”“是的,但不必如此死板。有些指令比较简单,可以很快完成,所以不需要计数。”“很好,但是如果计数不到100,在执行I/O操作时会被阻塞。如果还占用锁,那不是浪费资源吗?”小伙伴们急忙讨论起来。我想了想说:“就这样吧,结合两种情况。一般情况下,数量达到100就会释放一次锁,但是如果出现阻塞情况,就应该提前释放锁。怎么样?”大家点点头,达成一致,然后我们也给这把锁起了个名字:全局解释器锁GIL。自从用了GIL之后,大家在工作上更加有纪律了,从来没有出现过公共资源遭到破坏的情况。GIL升级版后,多核技术开始兴起,一个CPU可以同时执行多个线程。朋友们高兴地把消息传了出去。“老大,现在CPU多核了,我们可以一起执行,能不能把GIL去掉,这样我们就可以发挥多核的优势了?”“是啊,隔壁的Java线程老是笑话我们,只有一个线程在执行”说起来容易做起来难。多年来,我们一直都是这样工作的。如果一下子要撤掉,出了问题谁也不敢承担责任。“但是老板,这个GIL锁现在不公平”,新线程抱怨道。“哪里不公平?”“我正要执行代码,却发现锁在你手上,只好在那里等着,等了半天就睡着了。最后你放开的时候,操作系统把我叫醒了,准备去申请锁,却发现自己又抢了,浪费表情”,新帖满腹牢骚。“是的,老大,我也发现了,这不是偶然现象,我观察了很久,而且经常发生!我经常被唤醒,但我发现我一直忙于浪费CPU资源没什么,大家都很反感。一个线程哥们也发了言。我有点尴尬,“嗯,这确实是个问题”“还没完”,新帖继续:“现在按照字节码指令条数来统计,但是有的指令代码很简单,有的很复杂,导致同样数到100,有的线程可以运行很长时间,而有的线程运行很快就结束了,这是不公平的。”小伙伴们提的问题很重要,看来是时候升级GIL了。经过热烈的讨论,我们对原有的GIL进行了改进,采用了一种新的策略:不再计数,而是使用时间片:每个线程的执行时间片为5000微秒。为了保证GIL释放后,不会马上被自己抢走,新加了一把锁,实现强制线程切换。改进后终于公平了,大家也没什么好说的了,可以安心工作了。结论Python是一种解释型和执行型语言,具有强大的第三方库和跨平台能力。近年来,Python迎来了第二春,席卷爬虫、Web开发、机器学习等多个领域。但一直以来,Python最受诟病的地方就是它有一把锁:GIL,它让Python无法真正实现多线程执行,无法发挥多核CPU的高性能。其实这个锁和Python无关,而是负责解释执行Python的解释器:CPython的锅。CPython是用C语言编写的Python解释器,也是使用最广泛的Python解释器。一般在没有特殊说明的情况下,Python都是指这个CPython解释器。在Python诞生之初,多线程技术远没有今天这样普及,甚至多核CPU也是在Python诞生多年后才出现的。早期的解释器为了支持多线程,使用了粗糙的GIL来控制,方便简单,但也成为了CPython巨大的历史包袱。在Python3.2之前,Python使用一种简单的计数方式来统计控制每个线程的执行时间。之后引入更公平的时间片方式进行升级替换。在过去的二十年里,很多大牛都尝试过彻底去除GIL,但是都没有完美的成功。Python虽然没能彻底去掉GIL,但幸运的是,它提供了其他几种“曲线救国”方式实现并发:Ctypes通过编写C语言扩展与Python交互,在C语言层面绕过GIL,实现多-核心利用率。MultiProcessPython提供了MultiProcess,它以多进程的方式绕过了GIL。协程也称为用户模式线程。Python3.4之后新增了对协程的支持,这也为性能提升提供了一个选项。本文以第一人称白话的方式讲述了GIL在CPython解释器中的工作原理。你到底懂不懂呢?本文转载自微信♂“编程技术宇宙”,可通过以下二维码关注。转载本文请联系编程技术宇宙公众号。