相信各位都看到了Python官方最近憋出了一个“大招”,那就是Python 3.13支持全局禁用GIL锁,是的,这个困扰了Python玩家接近30年的一个问题似乎得到了解决,我们似乎也不会被C++玩家说我们Python速度慢了。那么具体性能可以提升多少,怎么去安装和设置这个版本呢,本文将会从理论,无GIL版本的安装,多线程代码的运行,与稳定的3.12版本运行的性能对比,线程池的设置问题等方面展开讨论和教学。
注:1.本次测试安装环境为Linux的树莓派5 +Ubuntu 24.04 和树莓派5的官方系统,测试Python版本为3.13.0b2,对比版本为3.11.2
2.第一部分为理论部分,如果想直接操作的可以直接从第二部分开始看起
一.Python的GIL锁
什么是全局解释器锁呢?相信各位都不陌生,其实就是一个专门针对于CPython设计的一个互斥锁,我们这里看一段Python官网对于GIL的解释:CPython解释器使用的机制是确保一次只有一个线程执行Python字节码。这样做可以简化CPython的实现,使对象模型(包括关键的内置类型,如字典)在并发访问时隐式安全。锁定整个解释器使得解释器更容易实现多线程,但也牺牲了多处理器机器所提供的大部分并行性。(原文为:The mechanism used by the CPython interpreter to assure that only one thread executes Python bytecode at a time. This simplifies the CPython implementation by making the object model (including critical built-in types such as dict) implicitly safe against concurrent access. Locking the entire interpreter makes it easier for the interpreter to be multi-threaded, at the expense of much of the parallelism afforded by multi-processor machines.)参考链接:官网
从Python官方给出的解释可以看到,全局解释器锁GIL存在的目的是为了能更好的使用多线程,同时牺牲了牺牲了多处理器机器所提供的大部分并行性,这就是我们日常津津乐道的:Python的多线程是假的多线程,那为什么当初Python之父明知这样会严重拖累Python的运行速度,但在设计这款语言的时候还要去弄一个GIL锁呢?其实和Python自身的内存管理(垃圾回收机制)有关,这里我用流程图和各位讲解一下:
这图中的垃圾回收机制其实包括三个部分:引用计数,标记清除,分代回收。 这里就不过多阐释了。
在这里我举了一个例子,就是一个非常简单的代码,代码想要去实现功能那就离不开Python解释器的帮助,在运行之后三个线程会同时对代码进行执行送往解释器去执行,在三个线程执行的时候,垃圾回收作为一个线程肯定也是要去拿给解释器去执行的,所以此时,4个线程就会用到4个CPU同时执行。那么,如果我们假设一种极端的情况呢?试想一下,线程2正好想申请一个num=1,刚刚从内存空间里面拿出来1,还没来得及去绑定num,这个时候垃圾回收线程看到这个1没有引用计数,就把这个1拿去回收了,那这个时候是不是就会出现数据错误的情况呢?
那GIL是怎么工作的呢?前面说过,GIL是一把互斥锁,那么联想一下互斥锁的运行逻辑,在线程1执行的时候,其他线程只能先等待线程1执行完之后再去执行,那这样是不是就“完美”解决因为垃圾回收线程导致数据错乱的情况。
那么这里说一下代价,其实代价很简单,也很残忍,那就是GIL会导致同一个进程下多个线程不可以同时进行,无法利用多核能力,就是我们常说的“假多线程”,这在Python刚刚诞生的年代似乎无伤大雅,毕竟那个年代计算机的性能都比较一般,但在信息产业大爆发的现在,多核运行已然成为常态,而GIL也成为了困住Python的一大枷锁,这也导致了Python运行速度与C/C++等运行速度拉开了巨大的差距(当然了,肯定是被人家拉开)。
这时肯定有小伙伴要问了,为什么Python官方突然在这个时候发出了可以禁用GIL锁版本的3.13呢?我个人看来可能有两个原因:第一个也许只是发布时间比较凑巧,因为Python从2.x到3.x,Python已经经历了数不清的版本迭代,作为Python语言一大“特色”的GIL想要清除是一件十分困难的事情。第二个可能是由于这些年来AI产业的大爆发,AI产业的发展某些意义上也促使了Python语言使用率的提升。
二.Python 3.13.0b2的安装及配置
好了,到了最激动人心的时候了,就是怎么去配置一个Python 3.13.0b2的环境,这里先向各位小伙伴们介绍一下作者本人的硬件配置吧!
硬件:树莓派5(4G)
系统:Ubuntu 24.04 安装3.13.0b2版本,树莓派5官方系统,安装3.11.2版本(用于对比)
注:win版本和mac版本还没测试过,后续有测试的话再更新其他版本的
在安装Python 3.13版本之前,我们要先安装好依赖,输入以下代码即可:
sudo apt-get install -y make build-essential libssl-dev zlib1g-dev sudo apt-get install -y libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm sudo apt-get install -y libncurses5-dev libncursesw5-dev xz-utils tk-dev
在安装完依赖之后,我们可以看一下官方的地址,这里有3.13.0b2的全部版本,如果以后还有更新的话参照这个地址进行修改:
https://www.python.org/ftp/python/3.13.x/x为后续的版本号,这里展示的0版本的Beta 2版本
在找好了地址之后,我们看到了适用于Linux系统的tgz版本(如图)
记号它的版本名字之后进入命令行,可以通过以下指令进行下载和解压:
sudo wget https://www.python.org/ftp/python/3.13.0/Python-3.13.0b2.tgzsudo tar -zxvf Python-3.13.0b2.tgz
这个时候解压完毕进入目录:
cd Python-3.13.0b2
下一步就是进行初始化了,这里我们参照一下Python官方的做法,我们可以参考以下Python官方的原文:
其实人家官方的说法已经很明白了,默认初始化时是打开GIL锁的,那么关掉的话只需要去--disable-gil就可以了,这里我们执行一下以下指令,这样安装的版本就禁用了GIL了
sudo ./configure --disable-gilsudo makesudo make install
然后就是修改软连接了,这一步比较麻烦,也容易出错,但也请各位细心配置,以防出错 !这里我们先查看一下之前Python的软连接位置——因为Ubuntu 24.04默认安装了3.12版本的Python,所以要做软连接的修改,当然如果你安装的Linux系统没有Python的话可以跳过删除原有软连接的部分。
这里我们先输入以下指令查看原本的python和pip地址:
which pythonwhich pip
一般情况下,它会显示这个地址:
/usr/bin/python /usr/bin/pip
这时可以通过“rm”指令删除原有的软连接:(注意:要先打开root权限)
su root #这时会要求你输入你自己设备的root密码,然后就获得了root权限sudo rm /usr/bin/python #删除Python的软连接sudo rm /usr/bin/pip #删除原来pip的软连接
这里多说一嘴哈,pip的软连接是必须删掉的,不然后续通过pip下载的外来库都不知道跑哪去了,当然如果你不想安装其他奇奇怪怪的库的话倒也无所谓,因为Python自带的库还是都有的
然后找到你Python安装的地址:
一般地址都是在:/usr/local 里面的一个分支里 ,这里我是安装在了 usr/local/lib/python3.13 里面,OK,这个时候看一看你Python里面有没有这个文件:python3.13t
记住哈,一定是带有t的版本,这个是无GIL特有的版本,然后记住它的地址,设置软连接:
sudo ln -s /usr/local....#输入你python3.13t所在的地址 /usr/bin/python#这里以我的地址举例,pip也是一样的办法:sudo ln -s /usr/local/lib/python3.13/python3.13t /usr/bin/pythonsudo ln -s /usr/local/lib/python3.13/pip3 /usr/bin/pip
然后呢,整个Python 3.13.0b2版本算是设置完了 ,这个时候看看效果吧:输入python
python
这个时候会跳出来这个彩色的界面,哈哈是的,3.13版本在命令行里面是有彩色显示的
然后就是检验GIL锁是否被禁用,输入以下Python代码即可测试:
import sysimport sysconfigprint(sysconfig.get_config_var("Py_GIL_DISABLED")) #输出为“1”时表示GIL已经被禁用print(sys._is_gil_enabled()) #输出为False表示GIL在运行时未被启用
输出结果应当是这样子:
OK,到这里你的Python 3.13.0b2的无GIL版本已经安装完了!