执行模型变体

既然我们已经学习了前一节中描述的内部执行流程,我应该提一下它反映了当今 Python 的标准实现,但并不真的是 Pyton 语言本身的一个必要条件。因此,执行模型容易随着时间而改变。事实上,已经有一些系统在某种程度上修改了图 2-2 中的模型图。在进一步学习前,让我们简要探索这些变体中最著名的那些。

执行模型变体——Python实现的可选方案

严格地讲,在本书此版本编写之际,有至少五种 Python 语言的实现 ——CPython, Jython, IronPython, Stackless PyPy。虽然在这些 Python 间有许多思想和工作的相互影响,但每一个仍是一个单独安装的软件系统,有自己的开发者和用户群体。其他的潜在候选包括 Cython Shed Skin 系统,但它们将作为优化工具在后面讨论,因为他们不实现标准的 Python 语言(前者是 Python/C 的混合体,后者是隐式静态类型的) 简而言之,CPython 是标准实现,也是大多数读者都希望使用的系统(如果你不确定,你也就很可能属于他们之中)。这也是本书使用的版本,虽然这里介绍的核心 Python 语言在替代品中几乎是完全一样的。所有其他的 Python 实现都有特定的目的和作用,虽然它们也能经常完成多数 Cpython 的功能。所有替代品都实现了同样的 Python 语言但以不同的方式执行程序。 比如,PyPy 是 CPython 的即插即用替换品,它能将大多数程序运行得快得多。同样,Jython 和 IronPython 是为不同运行时架构编译 Python 源码的完全独立的 Python 实现,提供了对 Java 和.NET 组件的直接访问。还可能从标准 CPython 程序访问 Java 和 .NET 软件 — 比如 JPypePython for .NET 系统,允许标准 CPython 代码去调用 Java 和 .NET 组件。 Jython 和 IronPython 通过提供 Python 语言的完整实现来提供了更完整的方案。下面是当今可用的最著名的 Python 实现的一个快速总结。

执行模型变体——Python实现的可选方案——CPython:标准

在与 Python 其他选项进行比较时,原来的标准实现通常被称为 CPython(否则就简单地称为 “Python”)。这个名称来自它是用可移植的 ANSI C 语言代码编写的事实。它有几种获取途径:从官网下载的 Python,通过 ActivePython 和 Enthought 发行版得到的,在大多数 Linux 和 Mac OS X 机器上自动安装好的。如果你已经在机器上发现了预装版本的 Python,很可能是 CPython,除非你的公司或组织正在以更多特殊的方式来使用 Python。 除非你想用 Python 来脚本化 Java 或 .NET 应用程序或发现 Stackless 或 PyPy 的好处非常吸引人,否则你很可能要使用标准的 CPython 系统。因为它是语言的标准实现,通常运行最快,最完整,且比可选的系统更新更及时和更健壮。图 2-2 反映了 CPython 的运行时架构

执行模型变体——Python实现的可选方案——Jython:用于Java的Python

Jython 系统(原来被称作 JPython)是 Python 语言的一个可选实现,定位是与 Java 编程语言集成。Jython 包含将 Python 源码编译成 Java 字节码并发送到 Java 虚拟机(JVM)的 Java 类。程序员仍照常在 .py 文本文件中编写 Python 语句;Jython 系统本质上只是用基于 Java 的等价物替换了图 2-2 最右边的两个气泡。 Jython 的目标是允许 Python 代码脚本化 Java 应用,这和 Cpython 允许 Python 去脚本化 C 和 C++ 组件非常像。它与 Java 的集成是非常无缝的。因为 Python 代码被翻译为 Java 字节码,它在运行时看起来和感觉上都像是一个真正的 Java 程序。Jython 脚本可以作为 Web 小程序和服务器小程序,构建基于 Java 的 GUI 等等。而且,Jython 包含了集成支持:允许 Python 代码导入和使用 Java 类好像它们是在 Python 中编码,允许 Java 代码将 Python 代码作为一门嵌入语言运行。然而,因为 Jython 比 Cpython 更慢,更不健壮,它通常被视作 Java 开发者寻找一门脚本语言作为 Java 语言的前端的有趣的工具。参见 Jython 的官网获取更多细节。

执行模型变体——Python实现的可选方案——IronPython: 用于 .NET 的Python

它是 Python 的第三个实现,比 CPython 和 Jython 都新,旨在允许 Python 程序与应用程序集成,这些程序被编写来与微软的 windows 平台上的 .NET 框架,以及 Linux 平台上的 Mono 开源代码等价物进行协作。.NET 和它的 C# 编程语言运行时系统都设计为一个语言中立的对象通信层,它们类似微软早期的 COM 模型。IronPython 允许 Python 程序作为客户端和服务器端组件,获得和其他.NET 语言的互访问性,并从它们的 Python 代码中利用如 Silverlight 框架这样的.NET 技术。 在实现上,IronPython 非常类似 Jython(并且,事实上,是同一个创造者开发的)—— 它用在.NET 环境中执行的等价物替换了图 2-2 的最后两个气泡。也类似 Jython,IronPython 有特殊关注点 —— 主要是将 Python 和.NET 组件集成的开发者感兴趣。之前被微软开发,现在是一个开源项目,IronPython 可能也可以利用一些重要的优化工具获取更好的性能。参考其官网和网上搜索的其他资料,获取更多细节。

执行模型变体——Python实现的可选方案——Stackless: 用于并发的Python

(除了前面所说的)还有其他目标更明确的运行 Python 程序的方案。比如,Stackless Python 系统是标准 CPython 语言的增强版本和重新实现,它关注并发能力。因为她不保存 C 语言调用堆栈的状态,Stackless Python 能让 Python 更容易移植到小堆栈架构(即内存有限)上,提供了高效的多处理选项,并促使了新颖的编程结构如协程的发展。 除了上述之外,Stackless 添加到 Python 的微线程是 Python 标准多任务工具如线程和进程的高效和轻量级替代品,并且许诺了更好的程序结构,更可读的代码,增强的程序员效率。CCP Games,EVE Online 的创始者,是一个著名的 Stackless Python 用户,也是一个有说服力的 Python 用户成功故事。到 Stackless 官网获取更多信息。

执行模型变体——Python实现的可选方案——PyPy: 加速Python

PyPy 系统是另一个标准 CPython 的重新实现,主要关注性能。它用 JIT(just-in-time / 及时) 编译器提供了快速的 Python 实现,为 “沙盒” 模型(可以在一个安全环境中运行未信任代码)提供了工具,并且默认支持前面章节的 Stackless Python 系统和它的微线程以支持大规模并发。 PyPy 是之前描述过的 Psyco JIT 的继任者,并且整合了一个完整的为速度而生的 Python 实现。JIT 真的只是 PVM(图 2-2 最右边的气泡)的一个扩展,为了更快的执行,它将部分字节码彻底地翻译为二进制机器代码。它是在程序运行时做这件事,而不是在预先运行的编辑步骤中,并且通过跟踪程序处理的对象的数据类型,能为动态的 Python 语言创建特定类型的机器代码。通过这种方式替代部分的字节码,程序在执行时会运行得越来越快。另外,一些 Python 程序在 PyPy 下还会占据更少的内存。 在写本书时,PyPy 执行 Python 2.7 代码(3.X 还不行)并且运行在 Intel x86(IA-32)和 x86_64 平台上(包括 windows,Linux,和最近的 Macs),ARM 和 PPC 的支持还在开发中。它运行大多数的 CPython 代码,然而 C 扩展模块通常必须被重新编译,且 PyPy 有一些微小但微妙的语言差异,包括会让一些常见的编码模式无效的垃圾回收语义。比如,它的非引用计数方案意味着临时文件可能没有关闭,输出缓冲区没有立即刷新,且在一些情况下可能需要人工调用 “关闭” 方法。 作为回报,代码可能运行得快许多。PyPy 当前声称在一系列的性能跑分程序中的速度超过 CPython 5.7 倍(根据 http://speed.pypy.org/)。在一些情况下,它利用动态优化机会的能力可以使 Python 代码运行得和 C 代码一样快,偶尔会更快。特别对重度算法或数字程序更是如此%E3%80%82%E5%9C%A8%E4%B8%80%E4%BA%9B%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E5%AE%83%E5%88%A9%E7%94%A8%E5%8A%A8%E6%80%81%E4%BC%98%E5%8C%96%E6%9C%BA%E4%BC%9A%E7%9A%84%E8%83%BD%E5%8A%9B%E5%8F%AF%E4%BB%A5%E4%BD%BFPython%E4%BB%A3%E7%A0%81%E8%BF%90%E8%A1%8C%E5%BE%97%E5%92%8CC%E4%BB%A3%E7%A0%81%E4%B8%80%E6%A0%B7%E5%BF%AB%EF%BC%8C%E5%81%B6%E5%B0%94%E4%BC%9A%E6%9B%B4%E5%BF%AB%E3%80%82%E7%89%B9%E5%88%AB%E5%AF%B9%E9%87%8D%E5%BA%A6%E7%AE%97%E6%B3%95%E6%88%96%E6%95%B0%E5%AD%97%E7%A8%8B%E5%BA%8F%E6%9B%B4%E6%98%AF%E5%A6%82%E6%AD%A4), 如果不是有 PyPy,这些程序都可能用 C 重写。 比如,在第 21 章中将会看到一个简单的跑分测试中,当前的 PyPy 运行得比 CPython 2.7 快 10 倍,比 CPython3.X 快 100 倍。虽然其他跑分测试会有所不同,但在许多领域,这样的加速可能是一个令人信服的优势,甚至比尖端的语言功能更有优势。同样重要的,在 PyPy 中内存也被优化了 —— 在一个发表的测试案例中,PyPy 只需要 247MB 在 10.3 秒内就完成了,而 CPython 需要 684MB 和 89 秒。 PyPy 的工具链也足够通用,可以支持其他语言,包括 Pyrolog(一个使用 PyPy 翻译器用 Python 编写的 Prolog 解释器)。搜索 PyPy 的网站获取更多信息。PyPy 目前在 pypy.org/ ,然而随着时间推移,通常的网络搜索也还是可以找到很多资料(即使网址改变)。对于当前性能的概述,请见 www.pypy.org/performance.html

执行模型变体——Python实现的可选方案——PyPy: 加速Python——注意

我刚写完这一节后,PyPy 2.0 就发布了评估版本,添加了对 ARM 处理器的支持,并且仍然只是 Python 2.X 的实现。根据它 2.0 评估版本说明: “PyPy 是一个非常兼容的 Python 解释器,几乎是 CPython 2.7.3 的即插即用替换品。由于其整合的跟踪 JIT 编译器,它非常快。这个版本支持运行 Linux 32/64, Mac OSX64 或 Windows 32 的 x86 机器。它还支持运行 Linux 的 ARM 机器。” 这个声明似乎是准确的。使用我们将在第 21 章中学习的计时工具,就我已经运行过的测试,PyPy 通常比 CPython 2.X 和 3.X 块一个数量级(10 的倍数),且有时甚至更好。尽管我的 Windows 测试电脑上的 PyPy 是 32 位的版本,而 CPython 却是一个更快的 64 位的编译版本,但确实如此! 自然,唯一真正重要的基准测试是你自己的代码,并且有些情况下 CPython 会胜出;比如,目前 PyPy 的文件迭代器可能会运行得更慢一点。尽管如此,考虑到 PyPy 关注性能,而非语言突变,且特别是它对数字领域的支持,目前许多人将 PyPy 视作 Python 的一个重要途径。如果你编写很费 CPU 的代码,PyPy 值得关注。 本文章首发在 LearnKu.com 网站上。

上一篇下一篇

Markdown 文本

纠错改进


执行模型变体——执行优化工具

CPython 和之前章节的大多数可选方案实现 Python 语言的方式都是相似的:编译源码为字节码然后在合适的虚拟机上执行字节码。一些系统(如 Cython 混合,Shed Skin C++ 翻译器,以及 PyPy 和 Psyco 中的 just-in-time 编译器)却尝试去优化基本的执行模型。在你 Python 生涯的这个时刻,这些系统并不是必须的知识,但快速了解一下它们在执行模型中的位置可能会从整体上更容易理解这个模型。

执行模型变体——执行优化工具——Cython: Python/C 混合体

Cython 系统(基于 Pyrex 项目完成的工作)是一个集合了 Python 代码和若干能力(调用 C 函数,使用对变量、参数和类属性的 C 类型声明)的混合语言。Cython 代码可以被编译为使用 Python/C API 的 C 代码,可能会被完全编译。虽然与标准 Python 不完全兼容,但 Cython 对封装外部 C 库和为 Python 编写高效的 C 扩展都很有用。参见官网获取当前状态和细节。

执行模型变体——执行优化工具——Shed Skin: Python 到 C++的翻译器

Shed Skin 是一个新兴系统,它采取了不同路径来执行 Python 程序 —— 它尝试将 Python 源码翻译为 C++ 代码,然后使用你电脑上的 C++ 编译器将 C++ 代码编译机器码。因此,它代表了一种与平台无关的运行 Python 代码的方法。 在我写下这些文字时,Shed Skin 仍处于积极开发中。它当前支持 Python 2.4 到 2.6 的代码,并且它将 Python 程序限制为隐式静态类型约束,这在大多数程序中都是普遍的但技术上来说不是正常的 Python,所以我们在这里不会进一步深入细节。然而,初始的结果显示了它有在执行速度方面战胜标准 Python 和类 Psyco 扩展的潜力。在网上搜索关于此项目当前状态的细节。

执行模型变体——执行优化工具——Psyco: 初始的 just-in-time 编译器

Psyco 系统并不是另一种 Python 实现,而是扩展字节码执行模型以加速程序运行的一个组件。当前,Psyco 已经有些是过时项目了:它仍然可以独立下载,但随着 Python 的演变已经过时,且不再被积极维护。作为替代,它的理念已经整合进入之前描述过的更完整的 PyPy 系统。然而,Psyco 探索出的理念的持续重要性使得它们值得快速了解一下。 根据图 2-2, Psyco 是 PVM 的一个增强版,它在程序运行时收集并使用类型信息来把部分的程序字节码彻底翻译为真正的二进制机器码以更快执行。Psyco 无需代码的修改或开发中一个单独的编译步骤,就完成了这个翻译。 大体上,当程序运行时,Psyco 收集关于正在被传递的对象种类的信息;这个信息能被用来产生为那些对象类型定制的高效机器码。一旦产生后,机器码就替换原始字节码的对应部分来加速程序整体执行。结果是使用 Psyco,程序的运行速度会变得越来越快。在理想案例中,在 Psyco 下的一些 Python 代码可能变得和编译好的 C 代码一样快。 因为这个从字节码的翻译发生在程序运行时,Psyco 被称为一种 just-in-time 编译器。 然而,Psyco 不同于一些读者可能已经在 Java 语言中见过的 JIT 编译器。事实上,Psyco 是一个专门化的 JIT 编译器 —— 它根据程序真实使用的数据类型来产生对应的机器码。比如,如果程序的一部分在不同时刻使用不同的数据类型,Psyco 可能会产生不同版本的机器码来支持不同的类型组合。 Psyco 被证明可以极大地加速某些 Python 代码。根据它的网页,Psyco 提供了 “2 到 100 倍的加速,通常是 4 倍,不修改 Python 解释器和源码,只是一个动态的可加载的 C 扩展模块。” 同样重要的,用纯 Python 编写的算法代码实现了最大程度的加速 —— 这恰恰可能是你通常迁移到 C 去优化的那种代码。要了解关于 Psyco 的更多信息,可以搜索网络或者看一下它的继任者 —— 之前描述过的 PyPy 项目。

执行模型变体——冻结的二进制文件 exe

有时当人们要求一个 “真实的” Python 编译器时,他们真正寻找的只是从 Python 程序生成独立二进制可执行文件的一种方法。这更多是一个打包和发布的主意而不是一个执行流的概念,但有一些关联。在网上获取的第三方工具的帮助下,将 Python 程序转换为真正的可执行文件(在 Python 世界中被称作冻结的二进制文件)是可能的。这些程序不需要 Python 的安装也可以运行。 冻结的二进制文件将程序文件中的字节码,以及 PVM(解释器)和程序需要的任何 Python 支持文件打包为一个单独的包。关于这个主题有一些变体,但最终结果是一个单独的二进制可执行程序(比如,在 Windows 上的 .exe 文件),它能轻松发送给客户。在图 2-2 中,似乎最右边的两个气泡 —— 字节码和 PVM—— 被合并为一个单独组件:一个冻结的二进制文件。 今天,许多系统可以产生冻结的二进制文件,它们的平台和功能都有所不同: Py2exe 只在 Windows 上,但有广泛的 Windows 支持;PyInstaller,类似于 py2exe 但也在 Linux 和 Mac OSX 上工作且能产生自安装的二进制文件;py2app 用来创建 Mac OS X 应用程序; 原来的工具,freeze;和 cx_freeze,它提供了 Python3.x 和跨平台支持。你可能不得不单独获取这些工具,而不能直接从 Python 本身的发行版中获得,但它们都是免费可得的。 这些工具也在持续进化,所以参考 Python 官网或你最爱的 web 搜索引擎来获取更多细节和状态。给你一个这些系统范围的概念:py2exe 能冻结使用 tkinter, PMW, wxPython 和 PyGTK GUI 库的独立程序;使用 pygame 游戏编程工具箱的程序;win32com 客户端程序;等等。 冻结的二进制文件和一个真正的编译器的输出不同 —— 它们通过虚拟机运行字节码。因此,除了可能的启动改进,冻结的二进制文件和原始源文件运行得一样快。冻结的二进制文件通常不小(包含 PVM),但按目前的标准,它们通常也不大。然而,因为 Python 嵌入在冻结的二进制文件中,它在运行程序的接收端是不需要安装的。而且,因为代码嵌入在冻结的二进制文件中,会更有效地隐藏于接收文件的人。 这个单一文件打包方案对商业软件的开发者特别有吸引力。比如,一个用 Python 编码的基于 tkinter 工具箱的用户界面程序可以被冻结为一个可执行文件且作为 CD 或 Web 上的自包含程序被分发。终端用户不需要安装(或甚至不需要知道)Python 来运行分发的程序。

执行模型变体——未来的可能性?

最后,注意到这里简述的运行时执行模型其实只是 Python 当前实现的人造产物(实现细节)而非语言本身。比如,一个完全的,传统的用于翻译 Python 源码为机器码的编译器可能会在本书的流行期内出现(虽然事实上在过去二十年没有一本书有过这样的情况,所以这种可能似乎不太可能!) 新字节码格式和实现变体也可以在未来被采用。比如:
  • 正在进行中的 Parrot 项目旨在为各种编程语言(包括 Python)提供一个通用的字节码,虚拟机和优化技术。Python 自己的 PVM 运行 Python 代码的效率要高于 Parrot(如在一个软件会议上,被一个 Pie 挑战展示得众所周知 —— 在网上搜索来获取细节),但不清楚关于 Python,Parrot 会如何的演化。参见其官网或整个网络获取细节。
  • 之前的 Unladen Swallow 项目 —— 一个被 Google 工程师开发的开源项目 —— 努力寻求让标准 Python 变快至少 5 倍,且快到足以在许多情况下代替 C 语言。这是 CPython(特别是 Python2.6)的一个优化分支,通过添加一个 JIT 到标准 Python,旨在兼容却更快。在我在 2012 年写下这些文字时,这个项目似乎已经快终结了(从它在 Python PEP 中被撤销(的情况)看,它即将死亡)。然而,它得到的经验教训可以以其他形式被利用起来;在网上搜索突破性进展。
虽然未来实现的方案可能在一定程度上更改 Python 的运行时结构,但字节码编译器看起来很可能将在未来一段时间继续成为标准。字节码的可移植性和运行时灵活性是许多 Python 系统的重要特性。而且,添加类型约束声明来支持静态编译很可能会破坏许多灵活性、简洁性、简单性和 Python 编程的整体原则。由于 Python 的高度动态特性,任何未来实现将很可能保留当前 PVM 的许多实现和设计(注:因为当前的 PVM 处理这种高度动态特性是如此优秀,如果随便修改,很可能还达不到现有效果)。 本文章首发在 LearnKu.com 网站上。

上一篇下一篇

Markdown 文本

纠错改进