关于 Python 3.13 你所需要知道的几点

news2024/11/26 11:49:27
alt

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

自20世纪80年代末,Guido Van Rossum在荷兰阿姆斯特丹东部的一个科技园区开始开发Python编程语言,它最初被设计为一种单线程的解释型语言。这到底是什么意思呢?

你可能会听说,编程语言分为解释型和编译型两种。那么Python属于哪一类?答案是:它属于两者。

实际上,你很少遇到完全由解释器直接从源代码进行解释的编程语言。对于解释型语言而言,可读的源代码通常会被转换成一种中间形式,也就是字节码。然后,解释器会逐条读取这些字节码并执行指令。

这里[1],“解释器”通常被称作“虚拟机”,尤其是在Java等其他语言中,它们和Python一样,都是通过虚拟机来处理字节码。在Java等语言中,更常见的做法是直接分发编译后的字节码,而Python应用则通常以源代码的形式分发(尽管现在,包也经常以wheel和sdist的形式部署)。

这种意义上的虚拟机在许多意想不到的地方都会出现,比如在PostScript格式中(PDF文件本质上就是编译后的PostScript),以及在字体渲染过程中。

如果你在自己的Python项目中看到过很多*.pyc文件,这些就是你的应用程序编译后的字节码。你可以像探索Java类文件一样,对这些pyc文件进行反编译和研究。

当们执行Python程序时,Python的执行程序会生成一系列指令流,即字节码,然后解释器会逐一读取并执行这些指令。

如果你启动了多个线程,它们将共享相同的内存空间(局部变量除外),因此它们都能访问和修改相同的数据对象。每个线程都有自己独立的栈和指令指针来执行字节码。

如果多个线程同时尝试访问或修改同一个对象,比如一个线程在向字典中添加内容,而另一个线程在读取字典,这时你有两个选择:

  1. 让字典和其他所有对象都实现线程安全,这需要付出很多努力,并且对于单线程应用来说会降低效率;
  2. 创建一个全局互斥锁(通常称为mutex),这样任何时候都只有一个线程能够执行字节码。

后者就是们所说的全局解释器锁(GIL)。而前者是Python开发者提到的“自由线程”模式。

另外值得一提的是,GIL简化了垃圾回收的过程,使其变得更快速。由于垃圾回收本身是一个复杂的话题,们在这里不深入讨论,但简单来说,Python会跟踪一个对象被引用的次数,当引用计数降到零时,Python就知道可以安全地删除这个对象了。如果多个线程同时创建和删除对不同对象的引用,可能会导致竞态条件和内存损坏,因此任何自由线程的版本都需要为所有对象使用原子计数的引用。

GIL还简化了Python的C扩展开发(例如使用Cython),因为你可以在开发时做一些关于线程安全的假设,这会让你的工作更加轻松。

为什么会有全局解释器锁?

尽管Python近年来变得非常流行,但它并不是一门新语言——它在20世纪80年代末诞生,首次发布于1991年2月20日(比稍微早一点)。在那个时代,计算机的形态与现在大相径庭。大多数程序都是单线程的,单个CPU核心的性能正以摩尔定律所描述的那样呈指数级增长。在那种环境下,对于大多数不使用多核的程序来说,牺牲单线程性能以换取线程安全是没有必要的。

而且,实现线程安全显然需要付出很多努力。

这并不是说你不能在Python中利用多核CPU。只是说,你不能通过线程来实现,而必须通过多个进程(例如使用multiprocessing模块)。

多进程与多线程的主要区别在于,每个进程都有自己的Python解释器和独立的内存空间。这意味着多个进程无法访问内存中的相同对象,而必须使用特殊的机制和通信方式来共享数据(可以参考“在进程间共享状态”和multiprocessing.Queue)。

值得一提的是,与多线程相比,使用多进程会有更大的开销,而且在数据共享上也更加困难。

然而,使用多线程并不总是像人们通常认为的那样糟糕。如果Python正在进行I/O操作,比如读取文件或发起网络请求,它会释放GIL,让其他线程得以运行。这意味着,如果你的程序主要是I/O密集型的,那么多线程通常会和多进程一样高效。只有在你的程序是CPU密集型的,GIL才会成为一个显著的问题。

为什么想要去掉全局解释器锁?

虽然移除GIL的呼声已经存在多年,但主要阻碍并非因为工程量大,而是因为这可能会让单线程程序的性能受损。

如今,电脑的单个CPU核心的性能提升速度已经放缓(尽管像苹果硅芯片这样的定制处理器架构取得了巨大进步),而核心数却在不断增加。这就意味着程序越来越需要利用多核的优势,而Python在多线程利用上的不足也日益凸显。

到了2021年,Sam Gross开发了一个无GIL的原型,这激发了Python决策委员会提出并投票通过了PEP 703——将CPython中的GIL变为可选。投票结果是肯定的,决策委员会决定接受这个提案,并计划分三个阶段逐步实施:

第一阶段:自由线程模式作为一个实验性功能,不是默认启用的。 第二阶段:自由线程模式得到官方支持,但不是默认选项。 第三阶段:自由线程模式成为默认设置。 从讨论中们可以看出,大家普遍不希望Python分裂成两个版本——一个有GIL,一个没有——而是希望在自由线程模式成为默认后,GIL最终被完全移除,只留下自由线程模式。

在关于GIL的讨论进行的同时,还有一个名为“更快的CPython”的项目在并行推进。这个项目得到了微软的资助,由Mark Shannon和Python之父Guido van Rossum领导。

这个团队的努力已经取得了显著的成果,尤其是在Python 3.11版本中,性能相比3.10有了大幅提升。

有了社区和决策委员会的支持,多核处理器的普及,以及“更快的CPython”项目的成功,现在正是开始实施GIL可选化计划的第一阶段的好时机。

即时编译器(JIT,Just-in-Time)

在这个Python新版本中,除了全局解释器锁(GIL)的重大变革外,还引入了一个实验性的即时编译器(JIT)。

即时编译器(JIT)是一种编译技术,它在执行前即时生成机器代码,与传统的提前编译(AOT)方式,如C语言的gcc或clang编译器不同。

之前们已经讨论过字节码和解释器。关键点是,在Python 3.13之前,解释器会逐条处理字节码,将其转换成机器代码后再执行。而现在,有了JIT编译器,字节码可以一次性转换成机器代码,并在需要时更新,不必每次都重新解释。

需要强调的是,Python 3.13中引入的这种即时编译器是一种“复制和修补”类型的JIT。这是一种2021年新提出的概念,其核心思想是使用一系列预设的模板——JIT编译器会寻找匹配这些模板的字节码,并用预设的机器代码进行替换。

传统的JIT编译器在功能上要强大得多,同时对内存的需求也更大,尤其是与Java或C#这类重度使用JIT编译的语言相比。(这也是Java程序占用较多内存的原因之一。)

JIT编译器的美妙之处在于它们可以在代码运行过程中进行适应。例如,JIT编译器会追踪代码的“热度”,并根据代码的执行频率进行增量优化,甚至可以根据程序的实际运行情况来指导优化过程(类似于AOT编译器中的性能分析优化)。这意味着JIT编译器不会在只运行一次的代码上浪费时间优化,而是对频繁执行的代码部分进行重点优化。

目前,Python 3.13中的JIT编译器还比较简单,不会进行过于复杂的操作,但它为Python性能的未来发展带来了极大的期待。

JIT编译器将带来哪些改变?

在短期内,JIT编译器的加入可能不会影响你编写或执行Python代码的方式。但它是Python解释器内部工作机制的一个激动人心的变化,这可能会在未来显著提升Python的性能。

具体来说,这为逐步的性能改进打开了大门,这些改进可能会逐渐提升Python的性能,使其与其它编程语言更具有竞争力。尽管如此,由于目前仍处于初期阶段,复制和修补的JIT技术还很新且轻量级,因此在们开始从JIT编译器中获得显著的性能提升之前,还需要进行更多的重大改进。

如何尝试 JIT?

JIT 编译器在 3.13 中是“实验性”的,并且没有提供开箱即用的支持(至少当使用 pyenv 下载 3.13.0rc2 时)。您可以通过执行以下操作来启用实验性 JIT 支持:

$ PYTHON_CONFIGURE_OPTS="--enable-experimental-jit" pyenv install 3.13-dev
python-build: use openssl@3 from homebrew
python-build: use readline from homebrew
Cloning https://github.com/python/cpython...
Installing Python-3.13-dev...
python-build: use tcl-tk from homebrew
python-build: use readline from homebrew
python-build: use ncurses from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.13-dev to /Users/drew.silcock/.pyenv/versions/3.13-dev
$ python -c 'import sysconfig;print("JIT enabled 🚀" if "-D_Py_JIT" in sysconfig.get_config_var("PY_CORE_CFLAGS") else "JIT disabled 😒")'
JIT enabled 🚀

你可以在PEP 744的讨论页面上找到一些额外的配置选项(比如,要启用JIT编译器,需要在程序运行时加上 -X jit=1 参数等)。

这个测试只能确认JIT是否在编译时被启用,而不能判断它当前是否正在工作状态(例如,是否在运行时被关闭)。虽然可以在程序运行时检查JIT是否启用,但这稍微复杂一些。这里有一个脚本可以帮助你弄清楚这一点(来源于PEP 744的讨论页面):

import _opcode
import types


def is_jitted(f: types.FunctionType) -> bool:
    for i in range(0, len(f.__code__.co_code), 2):
        try:
            _opcode.get_executor(f.__code__, i)
        except RuntimeError:
            # This isn't a JIT build:
            return False
        except ValueError:
            # No executor found:
            continue
        return True
    return False


def fibonacci(n):
    a, b = 01
    for _ in range(n):
        a, b = b, a + b
    return a


def main():
    fibonacci(100)
    if is_jitted(fibonacci):
        print("JIT enabled 🚀")
    else:
        print("Doesn't look like the JIT is enabled 🥱")



if __name__ == "__main__":
    main()

在PEP 744的讨论中,有人提到了PYTHON_JIT=0/1和-X jit=0/1这两种设置方式——测试后发现-X命令行选项似乎并没有什么效果,但是设置环境变量似乎能够达到预期的效果。

$ python is-jit.py
JIT enabled 🚀
$ PYTHON_JIT=0 python is-jit.py
Doesn't look like the JIT is enabled 🥱

总结

Python 3.13 版本带来了一些激动人心的全新概念和功能,这对 Python 的运行时环境来说是一个巨大的进步。虽然这些更新可能不会立即改变你编写和执行 Python 代码的方式,但可以预见,随着自由线程和即时编译器(JIT)技术的不断成熟和普及,它们将在未来几个月甚至几年内,逐渐提升 Python 代码的性能,尤其是对那些需要大量 CPU 计算的任务。

Reference
[1]

Source: https://drew.silcock.dev/blog/everything-you-need-to-know-about-python-3-13/?continueFlag=f23656d4bea3327c21483a69ed226eb0#what-does-the-performance-look-like

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2193067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++-容器适配器- stack、queue、priority_queue和仿函数

目录 1.什么是适配器 2.deque 1.简单了解结构 2.deque的缺陷 3.为什么选择deque作为stack和queue的底层默认容器 3.stack(栈) 4.queue(队列) 5.仿函数 6.priority_queue(优先级队列)(堆…

IDEA 2024.3 预览:把开发者感动到哭了

幸运的人, 一生都被童年治愈; 不幸的人, 一生都在治愈童年 只有勇敢的人 和有钱的人才能先享受世界 缘分就是我还不知道 会见到你就误打误撞般 遇见了你 最近 IDEA 又发布了最新的 2024.3 的预览版本 EAP,把开发者的心激动的…

躺平成长-第四周的开发日记

回顾自己的小程序,现在自己有饮食/跑步/养生操/学习/学历提升/等多样化的kp值计算公式页面,自己tarbar导航页面有两个内容,kp值计算,躺平显示,单纯这些功能自己使用下来,会感到一种疲惫!&#x…

详解Java中的堆内存

详解Java中的堆内存 堆是JVM运行数据区中的一块内存空间,它是线程共享的一块区域(注意了!!!),主要用来保存数组和对象实例等(其实对象有时候是不在堆中进行分配的,想要了…

霓虹灯数字时钟(可复制源代码)

文章目录 一、效果演示二、CodeHTMLCSSJavaScript 三、实现思路拆分CSS 部分JavaScript 部分 四、源代码 一、效果演示 文末可一键复制完整代码 二、Code HTML <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><…

我对软件工程的理解

1 引言 从事软件行业这么年&#xff0c;写了10年代码&#xff0c;又从事了多年的项目产品方面的工作&#xff0c;一些每天用到的软件工程的方法&#xff0c;虽然天天都在用但一些概念总感觉似是而非&#xff0c;正好借假期的时间&#xff0c;好好整理下&#xff0c;以供自己或…

AI配音(声音克隆)

Fish Audio: Free Generative AI Text To Speech & Voice Cloning 【【AI配音】终于找到免费 & 小白友好的声音克隆软件了&#xff01;真人相似度98%!】https://www.bilibili.com/video/BV1MwbFeCE2X?vd_source3cc3c07b09206097d0d8b0aefdf07958 我终于找到总这3款免…

Java中的封装、继承、多态

目录 封装 概念 包 继承 多态 向上转型 一、直接赋值 二、方法传参 三、返回值 向上转型注意事项 向下转型 格式 重写 重写和重载的区别 动态绑定 静态绑定和动态绑定 封装 概念 简单来说就是套壳屏蔽细节。 举例&#xff1a; 想要访问它们时需要一些“接口”…

Codeforces Rund 977 div2 个人题解(A~E1)

Codeforces Rund 977 div2 个人题解(A,B,C1,C2,E1) Dashboard - Codeforces Round 977 (Div. 2, based on COMPFEST 16 - Final Round) - Codeforces 火车头 #define _CRT_SECURE_NO_WARNINGS 1#include <algorithm> #include <array> #include <bitset> …

Java之二叉树的基本操作实现

1. 模拟实现二叉树前&#xff0c;我们要先表示树&#xff0c;首先定义一个内部类&#xff0c;当作二叉树节点 static class TreeNOde{char val;//存放二叉树的值TreeNOde left;//指向左子树的引用TreeNOde right;//指向右子树的引用//构造方法&#xff0c;用于实例化树的节点p…

信息学奥赛复赛复习13-CSP-J2021-02插入排序-排序稳定性、插入排序、sort排序、结构体、计数排序

PDF文档回复:20241006 1P7910 [CSP-J 2021] 插入排序 [题目描述] 插入排序是一种非常常见且简单的排序算法。小 Z 是一名大一的新生&#xff0c;今天 H 老师刚刚在上课的时候讲了插入排序算法。 假设比较两个元素的时间为 O(1)&#xff0c;则插入排序可以以 O(n^2) 的时间复…

第五节——转移表(让你不再害怕指针)

文章目录 制作简易计算器什么是转移表&#xff1f;switch函数实现函数指针数组实现 制作简易计算器 要求&#xff1a;制作一个简易计算器&#xff0c;可以进行* / - 等功能运算。 什么是转移表&#xff1f; 指的就是通过函数指针数组的方式通过数组去调用里面的函数&#x…

LeetCode讲解篇之239. 滑动窗口最大值

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们维护一个长度为k的窗口&#xff0c;然后窗口从数组最左边一直移动到最右边&#xff0c;记录过程中窗口中的最大值&#xff0c;就是答案 我们每次查询长度为k的窗口最大值是什么时间复杂度是O(k)的&#xff0…

软件验证与确认实验二-单元测试

目录 1. 实验目的及要求.................................................................................................... 3 2. 实验软硬件环境.................................................................................................... 3 …

idea插件市场安装没反应

https://plugins.jetbrains.com/idea重启后还是不行那就

163页PPT罗兰贝格品牌战略升级:华为案例启示与电器集团转型之路

罗兰贝格作为一家全球顶级的战略管理咨询公司&#xff0c;其品牌战略升级理念在多个行业中得到了广泛应用。以下将以华为案例为启示&#xff0c;探讨电器集团的转型之路&#xff0c;并融入罗兰贝格品牌战略升级的思想。 一、华为案例的启示 华为与罗兰贝格联合撰写的《数据存…

基于java+springboot的酒店预定网站、酒店客房管理系统

该系统是基于Java的酒店客房预订系统设计与实现。是给师弟开发的毕业设计。现将源代码开放出来&#xff0c;感兴趣的同学可以下载。 演示地址 前台地址&#xff1a; http://hotel.gitapp.cn 后台地址&#xff1a; http://hotel.gitapp.cn/admin 后台管理帐号&#xff1a; 用…

基于阻塞队列及环形队列的生产消费模型

目录 条件变量函数 等待条件满足 阻塞队列 升级版 信号量 POSIX信号量 环形队列 条件变量函数 等待条件满足 int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex); 参数&#xff1a; cond&#xff1a;要在这个条件变量上等待 mutex…

文字转语音免费的有哪些?这6款文字转语音软件让你配音效果炸满!

文字转语音免费的有哪些&#xff1f;文字转语音不管在有声朗读、配乐配音、影视旁白等实际生活场景中的应用都是非常广泛的&#xff0c;而目前语音识别文字的技术日渐成熟&#xff0c;已经渗透到生活办公的日常&#xff0c;包括我们的输入法自带语音转文字&#xff0c;都可以非…

105页PPT麦肯锡:煤炭贸易企业业务战略规划方案

麦肯锡作为全球领先的管理咨询公司&#xff0c;在协助客户进行企业业务战略规划方面形成了独特且系统的方法论。以下是对麦肯锡企业业务战略规划方法论的详细阐述&#xff1a; 一、战略规划的核心要素 战略方向的明确&#xff1a;战略规划的首要任务是帮助组织明确其愿景、使…