Python 兼容性
本页面的目标是指出在 PyPy 和 CPython 上运行 Python 之间的一些差异。
TL;DR¶
纯 Python 代码可以运行,但对象生命周期管理方面存在一些差异。使用 CPython C API 的模块可能可以运行,但无法通过 JIT 实现加速。我们鼓励库作者使用 CFFI 和 HPy 代替。
如果您正在寻找如何将 PyPy 与科学 Python 生态系统一起使用,我们建议您使用 conda,因为他们为 PyPy 打包了像 scikit-learn 和 SciPy 这样的常用库。
引用计数、__del__
和资源使用¶
纯 Python 代码中不会被修复的主要区别是 PyPy 不支持引用计数语义,以在对象的 __del__
被调用时“自动”释放状态。以下代码不会立即填充文件,而是在一段时间后,当 GC 进行收集并刷新输出时才会填充,因为只有在调用 __del__
方法时才会关闭文件。
正确的修复方法是
同样的问题——没有关闭你的文件——也会出现在你的程序打开大量文件而没有显式关闭它们的情况下。在这种情况下,你很容易达到系统对同时打开的文件描述符数量的限制。
PyPy 可以使用命令行选项 -X track-resources
运行(例如,pypy -X track-resources myprogram.py
)。当 GC 关闭未关闭的文件或套接字时,这会产生一个 ResourceWarning
。还会给出分配文件或套接字的位置的回溯,这有助于找到缺少 close()
的位置。
类似地,请记住,您必须 close()
一个未耗尽的生成器,以便立即执行其待处理的 finally
或 with
子句。
def mygen(): with foo: yield 42 for x in mygen(): if x == 42: break # foo.__exit__ is not run immediately! # fixed version: gen = mygen() try: for x in gen: if x == 42: break finally: gen.close()
更一般地说,__del__()
方法不像在 CPython 上那样具有预测性:它们在 PyPy 中“稍后运行”(或者如果程序在此期间完成运行,则根本不运行)。请参阅 此处了解更多详细信息。
为什么内存使用率如此之高?¶
请注意,PyPy 仅在 madvise() 系统调用(至少在 Linux、OS X、BSD)或 Windows 上之后才会将未使用的内存返回给操作系统。重要的是要意识到您可能不会在 top
中看到这一点。未使用的页面用 MADV_FREE
标记,它告诉系统“如果你在某个时候需要更多内存,请获取此页面”。只要内存充足,top
中的 RES
列可能会保持较高。(此规则的例外情况是那些没有 MADV_FREE
的系统,我们在其中使用 MADV_DONTNEED
,它强制降低 RES
。这包括 Linux <= 4.4。)
更多信息¶
可以在 我们的开发者网站 上找到更完整的已知差异列表。