RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1589411
Accepted
mrgervant
mrgervant
Asked:2024-08-04 03:19:34 +0000 UTC2024-08-04 03:19:34 +0000 UTC 2024-08-04 03:19:34 +0000 UTC

在 Python 中使用 JIT 编译器

  • 772

Python 3.13 预发布版本添加了实验性 JIT 编译器。也就是说,它可能会在秋季成为完整版本的一部分。据说它使代码运行得更快。

但是,如果我理解正确的话,JIT编译器可以通过不同的方式实现,因为Python 有几个非官方编译器:pypy / numba。因此,他们可以通过不同的方式或在不同的地方加速应用程序。

问题出现了 - JIT 编译器在 Python 中到底优化了什么,相应地,它们可以用于什么类型的任务?

python
  • 1 1 个回答
  • 102 Views

1 个回答

  • Voted
  1. Best Answer
    mrgervant
    2024-08-09T20:39:50Z2024-08-09T20:39:50Z

    以下是我找到的有关Python中JIT的信息

    但还需要其他可能的答案:

    • 并解释其他优化机制
    • 具有任何 JIT 编译器的实际使用经验

    您不应期望官方 JIT 在不久的将来对 Python 应用程序产生任何显着加速(正如@insolor指出的那样)。这源自PEP-744 -“JIT 编译”,到目前为止,该平台仅谈论其中一个平台的 5% 加速。

    不过,未来当开发者添加更多的优化机制时,性能提升将会更大。

    使用 JIT 编译器加速工作的一些选项

    替换慢指令

    虽然这种优化方法被归类为 JIT 编译器,但在 Python 3.11 版本中,优化被引入到解释器中(PEP-659 - “专用自适应解释器”) - 它用于优化字节码。

    在具有动态类型的语言(如Python)中,函数事先并不知道可能会进入其中的数据:

    def add(x, y):
        return x + y
    

    这个函数可以轻松处理数字和字符串 - 最主要的是类型匹配:

    add(1, 2)      # 3 - число
    add('1', '2')  # 12 - строка
    

    默认情况下,将使用操作码BINARY_OP- 使用它,将花费时间根据传递的参数(“+”)选择适当的命令:

    import dis
    
    def add(x, y):
        return x + y
    
    dis.dis(add, adaptive=True)
    
    # RESUME                   0
    # LOAD_FAST__LOAD_FAST     0 (x)
    # LOAD_FAST                1 (y)
    # BINARY_OP                0 (+)
    # RETURN_VALUE
    

    如果我们使用一个循环来调用add()带有整数的函数,那么根据先前调用的信息,我们可以用更快的专用指令替换缓慢的通用指令 BINARY_OP_ADD_INT:

    for i in range(100):
        add(i, 1)
    
    dis.dis(add, adaptive=True)
    
    # RESUME                   0
    # LOAD_FAST__LOAD_FAST     0 (x)
    # LOAD_FAST                1 (y)
    # BINARY_OP_ADD_INT        0 (+)
    # RETURN_VALUE
    

    但是,如果将非数字传递给某些调用,则会发生去优化- 返回到指令的基本执行。

    优化多个指令协同工作

    延续优化单个命令的想法,我们可以一次跟踪多个字节码的使用情况,并为它们的执行创建更快的路径。为此,首先执行跟踪(搜索经常使用的代码部分以进行优化),然后可以从字节码中删除一些微操作(micro-ops),并且只能使用剩余的微操作,而不是原始的完整字节码。

    考虑相同的示例,其中有一个循环,range(100)其中 2 个整数相加。

    因此,每个字节码命令都以相同的微操作开始——_CHECK_VALIDITY_AND_SET_IP这确保了生成代码的正确性,因为用户代码可以抛出异常、更改局部变量的值、更正内置函数等。但是,如果从收集的信息中我们知道这是对一系列数字进行简单迭代,将两个整数相加,那么我们可以将其删除。

    此外,在FOR_ITER_RANGE循环命令的代码中还有_ITER_CHECK_RANGE.它确保被迭代的对象仍然是一个范围。但在这种特殊情况下,我们知道它始终是一个范围,因此也可以删除保护性微操作。

    同样,BINARY_OP_ADD_INT 的微操作以_GUARD_BOTH_INT- 一个微操作开始,该微操作可防止操作数类型发生更改,并在发生这种情况时采用正常的缓慢路径。但是,类型不会改变,因此可以取消保护。

    因此,您可以不使用字节码,而是使用缩短的微操作(按照加法周期的示例,它们从 19 块减少到 10 块 - 几乎减少了 2 倍)。

    然而,执行这样的优化本身只会减慢程序的执行速度,因为创建和使用 10 个微操作的开销高于 7 个完整字节码。因此,它必须与JIT编译器结合使用,JIT编译器可以在编译过程中使用优化的执行路径。

    复制和补丁编译

    该版本的JIT编译计划从3.13开始在官方Python中使用(以及多指令优化方法)。在这里您可以阅读一篇描述此版本 JIT 编译的一般概念的文章。

    主要思想.o:使用 LLVM,以 ELF 格式预组装目标文件(模板),其中保留“孔”——在程序执行期间向其中插入数据的位置。 JIT 将程序解释期间生成的字节码指令(以上述方式优化)替换为机器代码的表示形式,同时将计算所需的数据替换为留下的“漏洞”。

    也就是说,程序将具有预先编写的机器代码片段,通过插入内存地址、寄存器地址、常量和其他参数来修补这些片段,从而加快工作速度。

    Copy-and-Patch编译没有任何特定的用法。因此,在本文中,研究人员优化了网络和数据库的工作。


    根据 Python 中 JIT 的可用信息,加速应用程序的关键是创建行为可预测且变量数据类型保持不变的函数。长周期运行的应用程序尤其受益。

    进一步的优化路径尚未公布。

    例如,IBM列出了 Java JIT 编译器中的 19 项优化。


    Python官方的优化方法和JIT编译的信息来源:

    • 文章将 JIT 编译器添加到 CPython(基于Brandt Bucher 的报告)- 英文
    • JIT in Python会议报告- 俄语

    Python 的其他 JIT 示例及其优化方式

    吡啶

    为了加快工作速度,PyPy 不仅使用跟踪,还使用метатрассировку​​.前缀“meta”意味着跟踪是在解释器运行时完成的,而不是在程序运行时完成的。 PyPy解释器可以监控自身的操作并优化代码执行路径。优化良好的解释器遵循机器代码的特定路径 - 这些代码已经可以在最终编译中使用。

    然而,这需要相当多的函数调用(大约需要执行该函数 3000 次才能更快地开始工作)。

    此外,由于 PyPy 本身本质上是用 Python(更准确地说RPython)编写的,因此它需要创建额外的层来执行用 C 编写的函数,这最终会减慢应用程序的速度。

    如果满足以下条件,使用 PyPy 可以加快代码速度:

    • 进程运行至少几秒钟,最好运行很长时间(JIT编译器将有足够的时间来收集信息)
    • 执行纯Python代码,而不是C库中的函数

    包含有关 PyPy 信息的文章:

    • 为什么有这么多Python?
    • JIT编译器是如何实现的

    努巴

    Numba 通过向代码添加装饰器来将 JIT 添加到带注释的 Python 代码中(无需更改解释器)。

    Numba 读取形式化函数的 Python 字节码,并将其与有关函数输入参数类型的信息组合起来。接下来,对代码进行分析和优化,然后使用 LLVM 编译器库生成函数的机器代码,以适应所用处理器的功能。每次调用该函数时都会使用此编译版本。

    然而,这些优化仅限于数学运算和 NumPy 库的运算。SciPy有一个单独的扩展。 Numba 不再理解其他库(特别是 pandas)。

    如果您的代码是面向数字的(大量数学)、经常使用 NumPy 和/或有大量循环,那么 Numba 将是一个不错的选择。


    有关 Numba 的信息的文章:

    • Python (+numba) 比 C 更快 - 认真的吗?! -第 1 部分和第 2 部分
    • 使用 numba 加速 Python

    • 3

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5