我已经编写了一个 Python 程序,并在 pypy 和 python 中运行了它。 我添加了一些计时打印来测量性能差异。 在某些情况下,速度提高了10倍,而在其他情况下没有变化。 有人能否解释一下在编写程序时是否有规则可以遵循,以利用 pypy 给出的潜在加速? 例如,避免某些语法,优先选择某些数据结构等。
我发现速度提高了12倍至1.5倍之间。
我已经编写了一个 Python 程序,并在 pypy 和 python 中运行了它。 我添加了一些计时打印来测量性能差异。 在某些情况下,速度提高了10倍,而在其他情况下没有变化。 有人能否解释一下在编写程序时是否有规则可以遵循,以利用 pypy 给出的潜在加速? 例如,避免某些语法,优先选择某些数据结构等。
我发现速度提高了12倍至1.5倍之间。
PyPy在处理与(小)整数/浮点数有关的纯数值密集型代码和包含< strong>热循环的情况下,通常比使用可变大小的动态整数/浮点数对象的C / C ++代码更快,因为它可以直接使用本地类型。但是,由于需要在运行时检查类型并编译代码,因此它仍然比本机编译的C / C ++代码慢。
PyPy不喜欢(大)动态代码。 它使用跟踪即时编译器,可以跟踪哪些代码部分更可能被执行,并在运行时动态编译此路径,如果经常执行,则会产生运行时开销。 当有许多执行路径动态更改时,JIT的开销可能很大,并且在最坏的情况下,PyPy可以选择不编译任何路径。 问题是PyPy回退解释器比CPython的解释器慢(由于能够跟踪和编译代码)。 支持一些动态特性,如帧内省,但速度较慢(因为代码不预计大量使用它们)。
对于短暂运行的脚本,PyPy不快,因为JIT必须在运行时编译代码,而JIT的开销或使用回退解释器(比CPython慢)可以高于对此类脚本使用CPython进行解释。
PyPy使用垃圾收集器(GC),而CPython使用自动引用计数(ARC)。 GC在分配/释放许多对象(特别是小临时对象)方面可能更快,但它们需要跟踪存活的对象以了解哪些对象已死亡,然后释放它们。 这意味着处理大量引用和常规对象分配的代码实际上可能会更慢。 这包括动态的基于图形的数据结构和树。
与CPython相比,C绑定API(C扩展和CTypes,但不包括CFFI)往往较慢(主要因为它首先是为CPython设计的)。 这意味着调用许多包装的C函数的粘合代码实际上会比使用PyPy慢。 最近完成了大量工作,显着提高了此情况下PyPy的性能,但据我所知,PyPy仍然较慢。 一个用例示例是对大型Numpy数组的操作(对于小型数组,嵌入式JITs如Numba肯定更好),以及CSV和pickling软件包。
字符串操作往往较慢,尤其是字符串连接。 一个原因是CPython使用高效算法进行字符串操作,这些算法在C中非常优化并且代码库庞大而复杂。 这对于小的PyPy团队来说是一项重要的工作,他们需要重新实现它并保持额外的JIT和GC的复杂性。 因此,操作可能没有很好地优化。 关于连接,低效性来自JIT无法优化中间副本。 话虽如此,需要避免字符串附加循环。
生成器往往比简单的基本循环要慢,越简单越好。人们不应该期望JIT在运行时执行复杂的昂贵优化,因为JIT的开销不应该与代码的其余部分相比太大(而PyPy无法提前知道代码所需的时间)。没有硬性规定。在 PyPy FAQ https://doc.pypy.org/en/latest/faq.html#how-fast-is-pypy 中有一些提示。PyPy 可以 JIT 热的 Python 代码,并且可能能够使存储一种对象类型(int、float、string)的列表、字典和元组更加高效。