提到Python,我们往往会提到CPython,C语言的Python实现,这时候PyPy就派上用场了。老实说,Python很慢,用Python(!)编写的Python在运行时的执行速度比CPython快4.4倍。这怎么可能?正如Python之父GuidovanRossum所说:“如果你想让你的代码运行得更快,你应该使用PyPy。”最早使用PyPy的程序员竞争的力量非常强大。有时,即使你花很多时间用Python写了一个解决方案,它最终也会失败,但在PyPy中运行相同的代码会成功。这是为什么?不同的方法Python是一种解释型语言,CPython逐行读取和执行源代码。解释型语言(包括JavaScript)有很多优点:容易编写元编程功能强大编译不会失败当然,它也有一些缺点:解析源代码时,性能消耗巨大编译不会失败正如你所看到的,它的优点和缺点包括“编译不会失败”。这有时基于不同的行为(如原型制作或生产),但我仍然倾向于将其视为缺点。而PyPy略有不同,它不是一个纯粹的解释器,而是实现了跟踪即时(JIT)编译。即时编译即时编译介于解释和传统的提前编译之间。即时编译器不执行源代码本身,而是生成一组可以立即执行的低级指令(通常是汇编)。这个例子可以帮助我们理解其中的区别。在编译型语言(C、C++、Rust)中,编译阶段严格按照开发环境划分。它生成一个可运行的二进制文件,然后将其发送到生产环境。在解释型语言中,情况恰恰相反:源代码(在*minification之后,helloJS)全部被推送到生产环境,由解释器执行。即时编译语言也提供源代码(或字节码,如Java或C#),但它是作为常规编译语言编译和运行的,而不是逐行解释。并不是说一种方法比另一种更好,每个用例都会根据其独特的需求做出正确的选择。但是,如果性能很关键并且您觉得使用Python解释器很舒服,那么您可以选择PyPy。跟踪即时编译与编译或解释一样,有不同的方法来实现即时编译。传统的方式是方法/函数作用域。当代码调用一个函数时,即时编译器获取它的源代码,编译它,并提供一个可执行的二进制文件。PyPy采用略有不同的方法,由Python的特性和用例决定。PyPy的编译器计算循环而不是方法调用。这是最有意义的,因为Python广泛应用于数据科学、机器学习、高级算法和数据结构。简而言之,PyPy是Python之上的优化层。PyPy并不像人们所理解的那样严格地处理循环。除了常规的for和while结构之外,如果PyPy检测到编译工作是值得的,它还会优化任意代码块。缺点图源:unsplash当然,PyPy也有缺点。即使它大大提高了性能,您也需要了解以下内容:并非所有Python都受支持。它支持你的大部分代码,但如果你处理低级CPython实现细节或者你有Cython绑定,它就不起作用。回溯到未来。目前PyPy的版本是3.4,Python目前稳定在3.8,但是回溯法是Python开发者擅长的技术。优化是好的,但不是写出糟糕代码的借口。如果人类无法阅读代码,PyPy如何理解代码?全局解释器锁仍然存在。如果执行繁重的多线程操作,请选择不同的实现。与任何工具一样,我们在采用之前应该考虑所有细节。然而,下次您登录Codeforces接受挑战时,试试PyPy。O(n^3)错误代码可能会通过,而在纯Python中只有O(nlogn)会通过。源代码尽管本文未涵盖CPython和PyPy的源代码,但这些文件在CPython(C代码)和PyPy(Python代码)中实现了阶乘函数。CPython:https://github.com/python/cpython/blob/master/Modules/mathmodule.c其他实现除了CPython和PyPy,还有另一个值得注意的Python实现:StacklessPython。它与Python相同,但没有全局解释器锁,这是《星战前夜》游戏后端使用的。IronPython是一种在.NET上实现的Python语言,它提供了Python和C#代码之间非常简单的互操作性。JPython是相同的,但使用Java。快去尝试使用PyPy体验代码加速吧!
