首页 后端开发 Python教程 Python 无需 GIL 即可实现高性能多线程的门户

Python 无需 GIL 即可实现高性能多线程的门户

Jan 06, 2025 pm 04:58 PM

介绍

Python 长期以来以其易用性和多功能性而闻名,但在 Python 社区中引发大量讨论的一个话题是全局解释器锁 (GIL)。 GIL 既是 Python 并发模型的保障,也是瓶颈,尤其是对于 CPU 密集型任务,否则这些任务可以利用多个 CPU 核心。然而,随着 Python 3.13 的发布,Python 开发人员有了一个突破性的新选项:禁用 GIL 的能力。本博客将探讨 GIL 是什么、为什么它成为多线程性能的障碍,以及如何在 Python 3.13 中检测和禁用 GIL 以释放真正的多线程性能。

什么是全局解释器锁(GIL)

全局解释器锁 (GIL) 是一个互斥锁,用于保护对 Python 对象的访问,防止多个本机线程同时执行 Python 字节码。这保证了Python程序的线程安全,但代价是并发执行。 GIL 使 Python 线程对于 I/O 密集型任务更加高效,但限制了它们对于 CPU 密集型任务的性能。

为什么 GIL 是多线程的瓶颈

Python 的 GIL 只允许一个线程同时执行,即使在多线程程序中也是如此。虽然这对于程序等待输入/输出操作的 I/O 密集型任务来说很好,但它严重限制了 CPU 密集型任务(如数字运算、数据分析或图像处理)的性能。

Python 3.13:在禁用 GIL 的情况下解锁多线程

使用 Python 3.13,开发人员可以选择在 Python 构建过程中禁用 GIL。但是,在预构建的 Python 发行版中无法禁用 GIL。相反,您必须使用 --disable-gil 选项从源代码编译 Python 3.13。

这个新选项为 CPU 密集型多线程任务中的真正并行性打开了大门,允许线程跨多个内核并行执行。

使用不带 GIL 的 Python 3.13 的先决条件

  • Python 3.13 源代码: 标准预构建二进制文件中不支持禁用 GIL。您必须使用 --disable-gil 标志从源代码构建 Python 3.13。
  • 多核 CPU: 您需要多核 CPU 才能从真正的多线程中受益,因为线程现在将跨多个内核并行运行。

在禁用 GIL 的情况下编译 Python 3.13

要使用 -X gil=0 标志禁用 GIL,您需要在启用 --disable-gil 标志的情况下从源代码编译 Python。具体方法如下

一步一步

  • 下载Python 3.13源代码 您首先需要从 Python 官方网站下载 Python 3.13 源代码 tarball。这是因为预构建的二进制文件(例如直接从 python.org 下载的二进制文件)未编译为支持禁用 GIL。您可以使用网络浏览器或使用 wget 甚至在终端中使用 curl 下载它
wget https://www.python.org/ftp/python/3.13.0/Python-3.13.0.tgz
登录后复制
  • 提取来源:
tar -xf Python-3.13.0.tgz
cd Python-3.13.0
登录后复制
  • 使用 --disable-gil 配置构建 您需要使用 --disable-gil 配置 Python 以支持禁用 GIL 的选项。
./configure --disable-gil
登录后复制
  • 编译并安装Python:
make
sudo make altinstall 
登录后复制
  • 如果 altinstall 步骤失败,则使用 --prefix 重新运行配置命令
./configure --disable-gil --prefix=$HOME/python3.13
登录后复制
  • 在指定目录下运行make altinstall 然后,运行 make altinstall 命令
make altinstall
登录后复制

如何在 Python 3.13 中检测 GIL

在Python 3.13中,您可以使用sys._is_gil_enabled()函数检查GIL是否启用或禁用。

import sys

def check_gil_status():
    if sys.version_info >= (3, 13):
        status = sys._is_gil_enabled()
        if status:
            print("GIL is currently enabled.")
        else:
            print("GIL is currently disabled.")
    else:
        print("Python version does not support GIL status detection.")

check_gil_status()
登录后复制

实践:使用 GIL 的 Python 多线程与无 GIL 的比较

开发以下 Python 代码是为了评估在 Python 3.13 中禁用 GIL 时的性能增益。该脚本同时执行八个线程,每个线程的任务是计算大数的素因数。通过利用真正的并行性,代码突出了无需 GIL 即可实现的增强性能。

#!/usr/bin/env python3
import sys
import sysconfig
import time
from threading import Thread
from multiprocessing import Process


# Decorator to measure execution time of functions
def calculate_execution_time(func):
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        execution_time = end_time - start_time
        print(f"{func.__name__} took {execution_time:.4f} seconds.")
        return result

    return wrapper


# Compute-intensive task: Iterative Fibonacci calculation
def compute_fibonacci(n):
    """Compute Fibonacci number for a given n iteratively."""
    a, b = 0, 1
    for _ in range(n):
        a, b = b, a + b
    return a


# Single-threaded task execution
@calculate_execution_time
def run_single_threaded(nums):
    for num in nums:
        compute_fibonacci(num)


# Multi-threaded task execution
@calculate_execution_time
def run_multi_threaded(nums):
    threads = [Thread(target=compute_fibonacci, args=(num,)) for num in nums]
    for thread in threads:
        thread.start()
    for thread in threads:
        thread.join()


# Multi-processing task execution
@calculate_execution_time
def run_multi_processing(nums):
    processes = [Process(target=compute_fibonacci, args=(num,)) for num in nums]
    for process in processes:
        process.start()
    for process in processes:
        process.join()


# Main execution function
def main():
    # Check Python version and GIL status for Python 3.13+
    print(f"Python Version: {sys.version}")

    py_version = float(".".join(sys.version.split()[0].split(".")[:2]))
    status = sysconfig.get_config_var("Py_GIL_DISABLED")

    if py_version >= 3.13:
        status = sys._is_gil_enabled()

    if status is None:
        print("GIL cannot be disabled for Python <= 3.12")
    elif status == 0:
        print("GIL is currently disabled")
    elif status == 1:
        print("GIL is currently active")

    # Run tasks on the same input size for comparison
    nums = [300000] * 8

    print("\nRunning Single-Threaded Task:")
    run_single_threaded(nums)

    print("\nRunning Multi-Threaded Task:")
    run_multi_threaded(nums)

    print("\nRunning Multi-Processing Task:")
    run_multi_processing(nums)


if __name__ == "__main__":
    main()

登录后复制

分析:

## Python 3.13 with GIL Disabled
Python Version: 3.13.0 experimental free-threading build (main, Oct 14 2024, 17:09:28) [Clang 14.0.0 (clang-1400.0.29.202)]
GIL is currently disabled

Running Single-Threaded Task:
run_single_threaded took 8.6587 seconds.

Running Multi-Threaded Task:
run_multi_threaded took 1.3885 seconds.

Running Multi-Processing Task:
run_multi_processing took 1.5953 seconds.

## Python 3.13 with GIL Enabled
Python Version: 3.13.0 experimental free-threading build (main, Oct 14 2024, 17:09:28) [Clang 14.0.0 (clang-1400.0.29.202)]
GIL is currently active

Running Single-Threaded Task:
run_single_threaded took 8.7108 seconds.

Running Multi-Threaded Task:
run_multi_threaded took 8.6645 seconds.

Running Multi-Processing Task:
run_multi_processing took 1.4530 seconds.

## Python 3.12 
Python Version: 3.12.6 (main, Sep  7 2024, 19:30:10) [Clang 14.0.0 (clang-1400.0.29.202)]
GIL cannot be disabled for Python <= 3.12

Running Single-Threaded Task:
run_single_threaded took 8.7004 seconds.

Running Multi-Threaded Task:
run_multi_threaded took 8.6297 seconds.

Running Multi-Processing Task:
run_multi_processing took 1.4876 seconds.
登录后复制

多线程性能:禁用 GIL 的真正好处在多线程场景中是显而易见的:

禁用 GIL (3.13) 时,执行时间为 1.5703 秒。
启用 GIL 后(3.13),执行时间为 8.5901 秒。
结果:禁用 GIL 使多线程任务的性能提高了约 81.7%。

Python The Gateway to High-Performance Multithreading Without GIL

Python The Gateway to High-Performance Multithreading Without GIL

该图表清楚地表明,在 Python 3.13 中禁用 GIL 可以显着提升多线程 CPU 密集型任务的性能,从而使 Python 能够高效地并行利用多个 CPU 核心。虽然单线程和多处理性能基本上不受影响,但多线程性能显示出显着改进,使 Python 3.13 成为依赖多线程的 CPU 密集型应用程序的游戏规则改变者。

但是,3.13之前的Python版本不支持禁用GIL,这也解释了为什么它们的多线程性能仍然与启用GIL的Python 3.13相似。早期版本中的这一限制继续限制 Python 充分利用多线程处理 CPU 密集型任务的能力。

禁用 GIL 之前的主要注意事项

在 Python 3.13 中禁用全局解释器锁 (GIL) 可以显着提高多线程 CPU 密集型任务的性能。但是,在此之前需要考虑几个重要因素:

  • 线程安全:如果没有 GIL,您必须使用锁或其他同步机制手动处理线程安全,以防止代码中的竞争条件。

  • 潜在的性能下降:细粒度锁定可能会引入争用,这可能会降低以前受益于 GIL 的单线程或 I/O 密集型任务的性能。

  • 与第三方库的兼容性:许多 C 扩展和库假设存在 GIL 以保证线程安全。禁用 GIL 可能需要更新这些库,以确保它们在多线程环境中正常工作。

  • 复杂的内存管理:禁用 GIL 会增加内存管理的复杂性,需要线程安全的内存处理,这会增加错误和错误的风险。

  • I/O 密集型任务: 禁用 GIL 为 I/O 密集型任务带来的好处有限,在这些任务中,像 asyncio 这样的非阻塞 I/O 机制可能更有效。

  • 调试困难:如果没有 GIL,由于竞争条件和死锁的可能性增加,调试多线程应用程序可能会变得更具挑战性。

  • 更高的内存使用量: 在没有 GIL 的情况下使用锁和管理线程状态会增加内存消耗,特别是在多线程应用程序中。

  • 嵌入式系统:禁用 GIL 可能会使 Python 与嵌入式系统中的多线程环境的集成变得复杂,需要付出更多努力才能有效集成。

  • 锁争用:在某些情况下,禁用 GIL 可能会导致线程之间出现锁争用,这可能会降低预期的性能改进。

GitHub 存储库

您可以在我的 GitHub 上找到此博客中示例的完整源代码:

Python GIL 性能分析

免责声明:

这是一个个人博客。本文表达的观点和意见仅代表作者的观点和意见,并不代表与作者有关​​联的任何组织或个人的专业或个人观点。

以上是Python 无需 GIL 即可实现高性能多线程的门户的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何解决Linux终端中查看Python版本时遇到的权限问题? 如何解决Linux终端中查看Python版本时遇到的权限问题? Apr 01, 2025 pm 05:09 PM

Linux终端中查看Python版本时遇到权限问题的解决方法当你在Linux终端中尝试查看Python的版本时,输入python...

在Python中如何高效地将一个DataFrame的整列复制到另一个结构不同的DataFrame中? 在Python中如何高效地将一个DataFrame的整列复制到另一个结构不同的DataFrame中? Apr 01, 2025 pm 11:15 PM

在使用Python的pandas库时,如何在两个结构不同的DataFrame之间进行整列复制是一个常见的问题。假设我们有两个Dat...

如何在10小时内通过项目和问题驱动的方式教计算机小白编程基础? 如何在10小时内通过项目和问题驱动的方式教计算机小白编程基础? Apr 02, 2025 am 07:18 AM

如何在10小时内教计算机小白编程基础?如果你只有10个小时来教计算机小白一些编程知识,你会选择教些什么�...

如何在使用 Fiddler Everywhere 进行中间人读取时避免被浏览器检测到? 如何在使用 Fiddler Everywhere 进行中间人读取时避免被浏览器检测到? Apr 02, 2025 am 07:15 AM

使用FiddlerEverywhere进行中间人读取时如何避免被检测到当你使用FiddlerEverywhere...

什么是正则表达式? 什么是正则表达式? Mar 20, 2025 pm 06:25 PM

正则表达式是在编程中进行模式匹配和文本操作的强大工具,从而提高了各种应用程序的文本处理效率。

Uvicorn是如何在没有serve_forever()的情况下持续监听HTTP请求的? Uvicorn是如何在没有serve_forever()的情况下持续监听HTTP请求的? Apr 01, 2025 pm 10:51 PM

Uvicorn是如何持续监听HTTP请求的?Uvicorn是一个基于ASGI的轻量级Web服务器,其核心功能之一便是监听HTTP请求并进�...

哪些流行的Python库及其用途? 哪些流行的Python库及其用途? Mar 21, 2025 pm 06:46 PM

本文讨论了诸如Numpy,Pandas,Matplotlib,Scikit-Learn,Tensorflow,Tensorflow,Django,Blask和请求等流行的Python库,并详细介绍了它们在科学计算,数据分析,可视化,机器学习,网络开发和H中的用途

Python中如何通过字符串动态创建对象并调用其方法? Python中如何通过字符串动态创建对象并调用其方法? Apr 01, 2025 pm 11:18 PM

在Python中,如何通过字符串动态创建对象并调用其方法?这是一个常见的编程需求,尤其在需要根据配置或运行...

See all articles