python的C扩展如何实现零开销

举报
码乐 发表于 2024/10/07 08:46:32 2024/10/07
【摘要】 1 简介这里简介一个python的新扩展接口,以窥语言优化之路。由于python属于高级语言,因此有众多复杂的语言结构,复杂结构的优点是可用性和安全的提高,可以适配更多的使用场景,其缺点就是导致性能的瓶颈。HPy 作为一个独立的底层接口,提供了一个用于用 C 语言扩展 Python 的新 API。换句话说,您使用#include <hpy.h> 而不是 .#include <Python....

1 简介

这里简介一个python的新扩展接口,以窥语言优化之路。由于python属于高级语言,因此有众多复杂的语言结构,复杂结构的优点是可用性和安全的提高,可以适配更多的使用场景,其缺点就是导致性能的瓶颈。

HPy 作为一个独立的底层接口,提供了一个用于用 C 语言扩展 Python 的新 API。换句话说,您使用#include <hpy.h> 而不是 .#include <Python.h>

  • HPy 的优势

CPython 的零开销:

用 HPy 编写的扩展以相同的方式运行,与CPython的C扩展性能一致。

在 PyPy、GraalPy 等替代实现上更快。

通用的二进制文件:为 HPy 通用 ABI 构建的扩展可以在 CPython、PyPy、GraalPython 等上未经修改地加载。

将旧版 C-API 调用与 HPy API 调用混合的迁移路径。一次即可迁移所有代码,扩展可以编译为通用二进制文件 适用于任何 CPython 版本、PyPy 或 GraalPy。

调试模式:

在调试模式下,您可以轻松识别常见问题,例如 如内存泄漏、对象的生命周期无效、API 的使用无效。HPy 调试模式可以是 在运行时激活,以便在通用二进制文件上为您检测Py_INCREF或Py_DECREF这些错误。

更好的 API:

标准的 Python/C API 显示其年龄。HPy 旨在 克服它的一些限制,更加一致,产生更好的质量 扩展,并使其更难引入 Bug。

可演化性:

正如 PEP 620 中对标准 Python/C API 的简要总结的那样 暴露了大量内部实现细节,这使得 发展 C API。HPy 没有这个问题,因为所有内部的 实现细节是隐藏的。

2 如何实现的零开销

  • HPY零开销的说明

HPy 是一种用于 Python 的 C 扩展 API,它被设计为现有 CPython C API 的改进和替代。

HPy 的目标是提供更高效、更可移植的方式来编写 Python 的 C 扩展,并且能够支持不同的 Python 解释器(如 PyPy、CPython 等)。

HPy 在设计上通过多种方式实现了“零开销”(zero overhead)的理念,尤其是在性能方面的优化。

  • 零开销设计如何实现

抽象层:

在传统的 CPython C API 中,很多操作是直接与 CPython 的内部数据结构耦合的。

这样虽然方便了扩展编写者,但在其他解释器(如 PyPy 或 GraalPython)上无法获得良好的性能,因为这些解释器的内部实现与 CPython 不同。
HPy 通过引入一层抽象,将扩展开发者与 Python 解释器的内部实现隔离开来。

例如,HPy 引入了 HPyContext 结构,它管理了对 Python 对象和函数的访问。这种抽象允许在不同的解释器上进行优化,而不影响扩展代码的行为。

因此在使用 HPy 的优化模式(如 HPy Universal)时,这些抽象层在 CPython 上没有性能损失,接近原生的 C API 性能。在其他解释器上,它们可以通过优化或即时编译(JIT)进一步提高性能。

更少的引用计数操作:

在 CPython 中,每个 Python 对象都带有引用计数(reference counting),这导致了大量的引用计数操作(如 Py_INCREF 和 Py_DECREF),它们在性能敏感的代码中可能成为瓶颈。
HPy 提供了一种机制,避免了在许多情况下显式地执行引用计数操作。特别是在临时对象的使用中,HPy 可以通过引入句柄(handle)机制,减少不必要的引用计数操作,从而减少开销。

  • 零开销的含义:

HPy 的句柄机制可以避免传统 C API 中频繁的引用计数增减,进而在不影响扩展功能的前提下减少开销。

多解释器的支持与优化

传统的 C API 仅仅是为 CPython 设计的,它深度依赖于 CPython 的实现细节。这使得使用同样的扩展代码在 PyPy 等解释器上运行时性能较差。

HPy 通过其抽象和可移植的 API 设计,允许不同的解释器为其自身的实现做优化。例如,PyPy 可以通过其 JIT 编译器大幅度提高 HPy 扩展的性能,而不会受到 CPython 引用计数等实现细节的约束。

  • 零开销的含义:

在不同的解释器上,HPy 能够充分利用解释器的优化机制,从而最大限度地提高性能。

对于 CPython,HPy 保持与现有 C API 性能相当的水平,而在 PyPy 等解释器上,HPy 可以做到无额外开销,甚至更高效。

局部句柄的优化:

HPy 引入了句柄系统来表示对 Python 对象的引用。在 HPy 的“局部句柄”(local handle)设计中,句柄的生命周期是局部的,只在特定的作用域内有效,这样就可以确保当不再需要这些句柄时,能够及时释放资源。

传统的 CPython API 中,开发者必须手动管理对象的生命周期,使用不当可能导致内存泄漏或其他问题。而 HPy 的局部句柄机制自动化了这一流程。

  • 零开销的含义:

通过局部句柄和生命周期管理,HPy 能够避免冗余的内存操作和复杂的对象管理,这在 CPython 之外的解释器中尤其重要,并且可以进一步提升性能。

高效的错误处理机制:

HPy 提供了比传统 C API 更高效的错误处理机制。在传统的 CPython C API 中,处理 Python 错误通常需要多次调用 Python 的内部函数,这会导致一定的性能开销。

HPy 通过引入专门的错误检查函数(如 HPyErr_Occurred 等),并将其与抽象的 HPyContext 结合,使得错误处理更加简洁和高效。

  • 零开销的含义

在错误处理场景中,HPy 可以通过优化 API 调用的次数,减少不必要的性能损失,同时简化扩展代码的编写。

延迟调用与内联优化:

HPy 提供了一些高级机制,可以延迟某些昂贵操作的执行,或者内联一些常见的函数调用。这些技术使得性能敏感的代码可以被进一步优化,而无需直接引入解释器内部的细节。

  • 零开销的意义:

通过内联和延迟执行,HPy 在保证代码可读性和移植性的同时,最大限度地提升了性能。

HPy 如何在不同解释器上实现“零开销”。

CPython 上的零开销:

对于 CPython,HPy 提供了一种“零开销模式”(HPy ABI),这个模式下,HPy 的性能接近甚至等同于原生的 C API。换句话说,如果你只针对 CPython 编写扩展,使用 HPy 代替传统 C API 不会带来明显的额外开销。

PyPy 等解释器上的零开销:

对于 PyPy 等基于 JIT(即时编译器)的解释器,HPy 的设计允许这些解释器在运行时生成更高效的代码,而不受限于 CPython 的实现细节。通过与解释器的协同优化,HPy 可以在这些平台上提供比传统 C API 更快的执行速度。

3 总结

小结HPy 实现接近“零开销”性能的方式:

使用更高效的抽象层,使扩展与具体的 Python 解释器实现解耦;
减少了不必要的引用计数操作,尤其是通过句柄机制优化临时对象的管理;
引入局部句柄和高效的错误处理机制,简化了代码编写并提高了执行效率;
在支持多解释器的同时,允许解释器对其自身做进一步的优化。
这些设计和优化使得 HPy 在保持与传统 C API 性能相当的同时,提供了更好的可移植性和潜在的性能提升,尤其是在 PyPy 等其他解释器上。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。