PyPy为什么能让Python比C还快?

「如果想让代码运行得更快,您应该使用 PyPy。」 - Python 之父 Guido van Rossum

对于研究人员来说,迅速把想法代码化并查看其是否行得通至关重要。Python 是能够实现这一目标的出色语言,它能够让人们专注于想法本身,而不必过度为代码格式等无聊的事情困扰。

但是,Python 有一个致命的缺点:速度比 C、C ++ 等语言慢很多。那么,构建一个 Python 原型测试想法之后,如何将其转变为快速且高性能的工具?通常来说,人们还要再进行一步工作:将 Python 代码手动转换为 C 语言的代码。但如果 Python 原型本身就可以运行得很快,那么转换代码的时间就可以做一些更有意义的事情。

而 PyPy,恰好可以解决这一问题。它能够让 Python 代码运行得比 C 还快。

import time
from termcolor import colored

start = time.time()
number = 0
for i in range(100000000):
    number += i
    
print(colored("FINISHED", "green"))
print(f"Ellapsed time: {time.time() - start} s")

为了证明 PyPy 的速度,使用默认的 Python 解释器和 PyPy 运行上述代码,执行一个从整数 0 加到 100,000,000 的循环, 然后打印出运行时间。运行结果如下:

运行时间 Python vs PyPy

这不是学术意义上的评估,但该结果是令人惊叹的。与大约需要 10 秒钟的默认 Python 解释器相比,PyPy 仅用 0.22 秒就完成了执行。而且无需进行任何更改就可以直接将 Python 代码放到 PyPy 上。而同一台计算机上,等效的 C 语言实现需要 0.32 秒,PyPy 甚至击败了最快的 C 语言。

为什么 PyPy 这么快?

尽管代码完全相同,但代码的执行方式却大不相同。PyPy 提升速度的秘诀是「即时编译( just-in-time compilation)」,即 JIT 编译。

提前编译

C、C ++、Swift、Haskell、Rust 等编程语言通常是提前编译(AOT 编译)的。这意味着用这些语言编写代码之后,编译器会将源代码转换成特定计算机架构可读的机器码。也就是说在执行程序时,执行的并不是原始源代码,而是机器码。

提前编译把源代码转化为机器代码

解释语言

与 C 语言等上述语言不同,Python、JavaScript、PHP 等语言采用另一种方法——解释语言。与将源代码转换为机器码相比,解释的过程中源代码是保持不变的。每次运行程序时,解释器都会逐行查看代码并运行。例如,每个 Web 浏览器都内置了 JavaScript 解释器。

解释器逐行运行程序

即时编译

PyPy 是利用即时编译来执行 Python 代码的。即 PyPy 不同于解释器,它并不会逐行运行代码,而是在执行程序前先将部分代码编译成机器码。

JIT 编译综合了提前编译和解释

如上图所示,而 PyPy 使用的 JIT 编译是解释和提前编译的结合,可以利用提前编译来提高性能,并提高解释型语言的灵活性和跨平台可用性。

感兴趣的小伙伴,赠送全套Python学习资料,包含面试题、简历资料等具体看下方。

一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。

img
img

二、Python必备开发工具

工具都帮大家整理好了,安装就可直接上手!img

三、最新Python学习笔记

当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。

img

四、Python视频合集

观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

img

五、实战案例

纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

img

六、面试宝典

在这里插入图片描述

在这里插入图片描述

简历模板在这里插入图片描述
若有侵权,请联系删除
Python的函数调用开销比C语言高,主要原因在于语言设计、运行时机制和执行环境的差异。 Python是一种动态类型、解释型语言,其函数调用过程涉及较多的运行时支持。例如,每次调用函数时都需要创建新的栈帧对象(PyFrameObject),并维护与解释器状态相关的上下文信息,这些操作显著增加了函数调用的开销。此外,Python的动态类型系统要求在运行时进行类型检查,进一步影响了调用效率。在某些情况下,使用lambda表达式或其他Python函数会重复设置Python堆栈帧,导致性能损耗[^2]。 相比之下,C语言是静态类型、编译型语言,其函数调用机制直接映射到硬件架构,调用过程高效。C语言的函数调用通过栈帧(stack frame)进行参数传递和返回地址保存,调用过程较为直接,开销较低。在C语言中,程序员可以对寄存器使用、内存布局进行精细控制,从而减少不必要的保存与恢复操作。此外,C语言的编译器通常支持多种优化手段,例如函数内联(inline),可以完全消除函数调用的栈操作,将函数体直接嵌入调用点,从而节省跳转和栈分配的开销[^3]。 Python的解释执行机制也导致了函数调用的额外开销。CPython解释器在执行Python代码时,需要将源代码编译为字节码,并在虚拟机中逐条执行这些字节码。这种机制相较于C语言的直接机器码执行,增加了额外的解释层,使得函数调用效率降低。为了提升性能,一些Python实现(如PyPy)引入了JIT(即时编译)技术,可以在运行时将部分Python代码编译为机器码,从而减少函数调用的开销,但这并不是CPython的默认行为[^2]。 在跨语言调用方面,Python可以通过扩展机制调用C语言函数,例如使用c extension、Cython或ctypes等方式。这些方法允许Python调用以C语言实现的高性能函数,从而在关键路径上获得接近C语言的性能。然而,每次跨语言调用都需要进行类型转换、参数封送等操作,这也会带来一定的性能损耗[^1]。 综上所述,Python的函数调用开销高于C语言的原因主要包括: 1. 动态类型系统导致的运行时类型检查; 2. 解释执行机制带来的额外解释层; 3. 函数调用过程中需要创建和维护PyFrameObject对象; 4. 使用lambda或其他Python函数时重复设置Python堆栈帧; 5.语言调用需要进行类型转换和参数封送操作。 这些因素共同导致了Python函数调用的性能劣势。 ```python # 示例:Python函数调用 def add(a, b): return a + b result = add(3, 4) ``` ```c // 示例:C函数调用 #include <stdio.h> int add(int a, int b) { return a + b; } int main() { int result = add(3, 4); printf("%d\n", result); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值