Python3.13 rc2 自由线程性能实验

如果你曾经尝试通过多线程提升Python的性能,那么你肯定遇到过一个老对手——全局解释器锁(GIL)。这个讨人厌的小家伙会阻止Python线程真正实现并行运行。但是嘿!GIL已经是个老生常谈的话题了,如今,随着Python 3.13推出了实验性的NO-GIL(自由线程)版本,终于有机会动手试试看这到底意味着什么!

在这里插入图片描述
正式版本预计在假期推出,现在目前是 RC2 版本

GIL是个啥?为什么Python需要它?

简单来说,GIL是Python的“防守大将”,确保同一时刻只有一个线程在执行Python字节码。那这是为什么呢?Python依赖引用计数来进行内存管理。如果多个线程同时修改对象的引用计数,而没有锁机制的保护,数据可能会遭到破坏。

也就是说,GIL存在让Python的内存管理更简单,线程更安全,但代价就是:CPU密集型任务无法真正并行。不管你的CPU有多少核心,线程在遇到计算密集型任务时,总是只能一个个排队执行。

Python 3.13 与 NO-GIL 实验版登场

Python 3.13的NO-GIL实验(即自由线程)试图打破这种限制。通过移除GIL,Python线程可以真正实现并行,充分利用多核处理器的优势。这听起来是不是很棒?

那么,接下来我们看看我通过Docker在Python 3.13的GIL版本和NO-GIL版本上进行的一些实验,看看实际效果如何。

实验设置

我进行了两组测试:

  • 计算密集型任务:一个简单的循环,进行大量的数字相加。
  • I/O密集型任务:通过多线程从 https://example.com 获取网页内容。

测试脚本如下:

import sys
import time
import requests
import threading

# 例子:输出 Python 版本
print(f"Python version: {sys.version}")

# 模拟任务
def compute_task():
    total = 0
    for i in range(10**7):
        total += i

# 记录开始时间
start_time = time.time()

# 创建并启动线程
threads = [threading.Thread(target=compute_task) for _ in range(100)]
for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

# 记录结束时间
end_time = time.time()

# 输出执行时间
print(f"Total execution time for compute_task: {end_time - start_time:.4f} seconds")


def fetch_url():
    response = requests.get('https://example.com')
    return response.content

# 记录开始时间
start_time = time.time()

# 创建并启动线程
threads = [threading.Thread(target=fetch_url) for _ in range(200)]
for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

# 记录结束时间
end_time = time.time()

# 输出执行时间
print(f"Total execution time for fetch_url: {end_time - start_time:.4f} seconds")

python镜像

使用docker 镜像,免除编译

sudo docker pull registry.gitlab.com/python-devs/ci-images:active 
sudo docker run -it registry.gitlab.com/python-devs/ci-images:active /bin/bash
sudo docker run registry.gitlab.com/python-devs/ci-images:active python3.13t -c "import sys; print(sys.version)"
# 输出:3.13.0rc2 experimental free-threading build (main, Sep 25 2024, 17:05:31) [GCC 13.2.0]

# 把 3.13t 改成 3.13
# 输出: 3.13.0rc2 (main, Sep 25 2024, 17:09:53) [GCC 13.2.0]

可以看到有 free-threading 版本的,带 GIL 的版本

测试

  • GIL 版本测试命令
sudo docker run --rm -v /opt/bdp/data01/ :/usr/src/ -w /usr/src/ registry.gitlab.com/python-devs/ci-images:active bash -c "python3.13 -m venv venv13 && source venv13/bin/activate && pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple && python3.13 test.py"

# 输出:
Python version: 3.13.0rc2 (main, Sep 25 2024, 17:09:53) [GCC 13.2.0]
Total execution time for compute_task: 45.5343 seconds
Total execution time for fetch_url: 6.4674 seconds
  • NO-GIL 版本测试命令
sudo docker run --rm -v /opt/bdp/data01/ :/usr/src/ -w /usr/src/ registry.gitlab.com/python-devs/ci-images:active bash -c "python3.13t -m venv venv13t && source venv13t/bin/activate && pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple && python3.13t test.py"

# 输出:
Python version: 3.13.0rc2 experimental free-threading build (main, Sep 25 2024, 17:05:31) [GCC 13.2.0]
Total execution time for compute_task: 3.7221 seconds
Total execution time for fetch_url: 1.9412 seconds
版本计算密集型任务IO密集型任务
GIL45.5s6.5s
NO-GIL3.7s1.9s
提升幅度12.30 倍3.42 倍

可以看到 NO-GIL 版本的 python 在计算密集型的任务上,有非常大的性能提升

NO-GIL 的优势与挑战

从实验中可以看出,NO-GIL版本对计算密集型任务的提升尤为显著。通过自由线程,Python终于能在多核处理器上高效并行处理任务,这对处理大量数据、AI训练等需要高性能计算的场景极具吸引力。

然而,NO-GIL的实现并非没有挑战:

  • 兼容性问题:许多第三方扩展库依赖于GIL的存在,移除GIL可能会导致这些库出现线程安全问题。
  • 复杂性增加:没有了GIL,Python的内存管理和多线程设计会变得更加复杂,程序员需要更小心地处理线程间的竞争条件。
  • 性能调优:虽然NO-GIL在计算密集型任务中表现出色,但在某些场景下,线程切换和同步的开销可能反而拖慢速度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Michael阿明

如果可以,请点赞留言支持我哦!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值