python3.14 无GIL锁简单测试

导入

就像标题所说,python 3.14版本终于解开了全局解释器锁,也就是GIL的限制,就在今天,3.14版本正式发布了。因此,就简单了进行了一下测试,久违的写一篇博客,当作是见证一下这个python巨大改变的版本。

python开发者的一个常识性的认知,就是以前的python是没有真正的并行的,多核CPU也只能同时调度一个线程,因此只存在并发,而没有并行。这就造成了python只适合处理IO密集型任务,而不适合处理CPU密集型任务,但就在今天,这个认知显然要改变了,因此就写一个简单的CPU密集型的测试,来见证一下这个改变。

测试代码

#test_no_GIL.py
import threading
import time


def is_prime(n):
    """一个简单的质数判断函数"""
    if n <= 1:
        return False
    if n <= 3:
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    while i * i <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i += 6
    return True


def cpu_task(start, end, results, index):
    """CPU 密集型任务:计算指定范围内的质数个数"""
    count = 0
    for num in range(start, end):
        if is_prime(num):
            count += 1
    results[index] = count


def run_cpu_test(num_threads=4):
    """运行 CPU 密集型测试"""
    total_numbers = 1000000
    chunk_size = total_numbers // num_threads
    ranges = [(i * chunk_size, (i + 1) * chunk_size) for i in range(num_threads)]
    # 确保最后一个范围包含到 total_numbers
    ranges[-1] = (ranges[-1][0], total_numbers)

    threads = []
    results = [0] * num_threads
    start_time = time.time()

    for i in range(num_threads):
        thread = threading.Thread(
            target=cpu_task, args=(ranges[i][0], ranges[i][1], results, i)
        )
        threads.append(thread)
        thread.start()

    for thread in threads:
        thread.join()

    end_time = time.time()
    total_primes = sum(results)
    print(
        f"CPU密集型测试 - 线程数: {num_threads}, 总质数: {total_primes}, 耗时: {end_time - start_time:.2f} 秒"
    )


if __name__ == "__main__":
    print("--- CPU 密集型测试 ---")
    # 单线程测试
    run_cpu_test(num_threads=1)
    # 多线程测试 (例如 4 个线程)
    run_cpu_test(num_threads=4)

一个简单的计算指定1,000,000范围内的质数个数的例子,显然是纯粹的CPU密集计算型的任务,我们先用以前的python来运行一下:python test_no_GIL.py

--- CPU 密集型测试 ---
CPU密集型测试 - 线程数: 1, 总质数: 78498, 耗时: 3.12 秒
CPU密集型测试 - 线程数: 4, 总质数: 78498, 耗时: 2.98 秒

--- CPU 密集型测试 ---
CPU密集型测试 - 线程数: 1, 总质数: 78498, 耗时: 3.56 秒
CPU密集型测试 - 线程数: 4, 总质数: 78498, 耗时: 2.88 秒 

--- CPU 密集型测试 ---
CPU密集型测试 - 线程数: 1, 总质数: 78498, 耗时: 2.97 秒
CPU密集型测试 - 线程数: 4, 总质数: 78498, 耗时: 3.00 秒

测试了三次,结果如上所示,可以看到单线程和4线程的耗时都是3秒左右,几乎是没区别的,也正符合我们的认知。

然后使用无锁的python 3.14来进行测试,这里用uvx来使用临时的python3.14t无锁版本虚拟环境来运行测试,uvx python@3.14t test_no_GIL.py,uv工具会自动在cache目录下载配置好python3.14t的临时虚拟环境,不会污染全局环境。

--- CPU 密集型测试 ---
CPU密集型测试 - 线程数: 1, 总质数: 78498, 耗时: 2.54 秒
CPU密集型测试 - 线程数: 4, 总质数: 78498, 耗时: 0.94 秒 

--- CPU 密集型测试 ---
CPU密集型测试 - 线程数: 1, 总质数: 78498, 耗时: 2.39 秒
CPU密集型测试 - 线程数: 4, 总质数: 78498, 耗时: 0.93 秒 

--- CPU 密集型测试 ---
CPU密集型测试 - 线程数: 1, 总质数: 78498, 耗时: 2.04 秒
CPU密集型测试 - 线程数: 4, 总质数: 78498, 耗时: 0.94 秒

同样运行三次,效果如上所示,结果不用多说,确实是并行运行,有效的利用了多核,减少了运行时间。