Cython 编程学习指南第二版(二)

原文:zh.annas-archive.org/md5/0bc691743f26fcdcabcb6840b706a834

译者:飞龙

协议:CC BY-NC-SA 4.0

第六章. 进一步阅读

到目前为止,在这本书中,我们已经探讨了使用 Cython 的基本和高级主题。但,这并没有结束;还有更多您可以探索的主题。

概述

本章我们将讨论的其他主题包括 OpenMP 支持、Cython 预处理器以及其他相关项目。考虑其他 Python 实现,如 PyPy 或使其与 Python 3 兼容。不仅如此,还有哪些 Cython 替代方案和相关 Cython 工具可供使用。我们将探讨 numba 和 Parakeet,并查看 numpy 作为 Cython 的旗舰用法。

OpenMP 支持

OpenMP 是一种用于共享内存并行计算的语言标准 API;它在多个开源项目中使用,例如 ImageMagick (www.imagemagick.org/),旨在加快大型图像处理的速度。Cython 对此编译器扩展提供了一些支持。但是,您必须意识到您需要使用支持 OpenMP 的编译器,如 GCC 或 MSVC。Clang/LLVM 目前还没有 OpenMP 支持。这并不是解释何时以及为什么使用 OpenMP 的地方,因为它是一个庞大的主题,但您应该查看以下网站:docs.cython.org/src/userguide/parallelism.html

编译时预处理器

在编译时,类似于 C/C++,我们有 C 预处理器来决定编译什么,这主要基于条件、定义和两者的混合。在 Cython 中,我们可以使用 IFELIFELSEDEF 来复制其中的一些行为。以下代码行展示了这一示例:

DEF myConstant = "hello cython"

我们还可以从 Cython 编译器访问预定义的常量 os.uname

  • UNAME_SYSNAME

  • UNAME_NODENAME

  • UNAME_RELEASE

  • UNAME_VERSION

  • UNAME_MACHINE

我们也可以对这些内容进行条件表达式,如下所示:

IF UNAME_SYSNAME == "Windows":
    include "windows.pyx"
ELSE:
    include "unix.pyx"

您还可以在条件表达式中使用 ELIF。如果您将某些内容与 C 程序中的头文件进行比较,您将看到如何在 Cython 中复制基本的 C 预处理器行为。这为您快速了解如何在头文件中复制 C 预处理器使用提供了思路。

Python 3

将代码迁移到 Python 3 可能很痛苦,但围绕这个主题的阅读表明,人们通过仅用 Cython 编译他们的模块而不是实际迁移代码,已经成功地将他们的代码迁移到 3.x。使用 Cython,您可以通过以下方式指定输出以符合 Python 3 API:

$ cython -3 <options>

这将确保您输出的是 Python 3 内容,而不是默认的 -2 参数,该参数为 2.x 标准生成。

PyPy

PyPy 已成为标准 Python 实现的流行替代品。更重要的是,现在许多公司(从小到大)正在将其用于生产环境以提升性能和可扩展性。PyPy 与正常的 CPython 有何不同?虽然后者是一个传统的解释器,但前者是一个完整的虚拟机。它在大多数相关架构上维护了一个即时编译器后端,以进行运行时优化。

要在 PyPy 上运行 Cython 化的模块,取决于它们的 cpyext 模拟层。这还不完整,有许多不一致之处。但是,如果你勇敢并愿意尝试,它将随着每个版本的发布而变得越来越好。

AutoPXD

当涉及到编写 Cython 模块时,你大部分的工作将包括正确获取你的 pxd 声明,以便正确操作原生代码。有几个项目试图创建一个编译器,读取 C/C++ 头文件并生成你的 pxd 声明作为输出。主要问题是维护一个完全符合 C 和 C++ 解析器的编译器。我的 Google Summer of Code 项目的一部分是使用 Python 插件系统作为 GCC 的一部分,以重用 GCC 的代码来解析 C/C++ 代码。该插件可以拦截声明、类型和原型。它还没有完全准备好使用,还有其他类似的项目试图解决同样的问题。更多信息可以在github.com/cython/cython/wiki/AutoPxd找到。

Pyrex 和 Cython

Cython 是 Pyrex 的衍生产品。然而,Pyrex 更加原始,Cython 为我们提供了更强大的类型和功能,以及优化和异常处理的信心。

SWIG 和 Cython

总体来说,如果你将 SWIG (swig.org/) 视为编写原生 Python 模块的方法,你可能会被误导,认为 Cython 和 SWIG 是相似的。SWIG 主要用于编写语言绑定的包装器。例如,如果你有一些如下所示的 C 代码:

int myFunction (int, const char *){}

你可以按照以下方式编写 SWIG 接口文件:

/* example.i */
%module example
%{
  extern int myFunction (int, const char *);
...
%}

使用以下命令编译:

$ swig -python example.i

你可以像编译 Cython 输出一样编译和链接模块,因为这将生成必要的 C 代码。如果你只想创建一个基本的模块,从 Python 调用 C,这是可以的。但 Cython 为用户提供得更多。

Cython 发展得更加完善和优化,它真正理解如何与 C 类型和工作内存管理协同工作,以及如何处理异常。使用 SWIG,你无法操作数据;你只能从 Python 调用 C 端的函数。在 Cython 中,我们可以从 Python 调用 C,反之亦然。类型转换功能非常强大;不仅如此,我们还可以将 C 类型封装成真正的 Python 类,使 C 数据感觉更像是 Pythonic。

来自第五章 高级 Cython 的 XML 示例,我们能够插入 import 替换?这是由于 Cython 的类型转换,API 非常 Pythonic。我们不仅可以把 C 类型包装成 Pythonic 对象,而且还让 Cython 生成 Python 执行此操作所需的样板代码,而无需将事物包装成类。更重要的是,Cython 为用户生成了更多优化的代码。

Cython 和 NumPy

NumPy 是一个科学库,旨在提供类似于 MATLAB 的功能,MATLAB 是一个付费的专有数学包。由于你可以使用 C 类型从高度计算密集型的代码中获得更多性能,NumPy 在 Cython 用户中非常受欢迎。在 Cython 中,你可以如下导入这个库:

import numpy as np
cimport numpy as np

np.import_array()

你可以如下访问完整的 Python API:

np.PyArray_ITER_NOTDONE

因此,你可以在 API 的一个非常本地区域与迭代器集成。这允许 NumPy 用户在通过以下方式使用本地类型时获得很多速度:

cdef double * val = (<double*>np.PyArray_MultiIter_DATA(it, 0))[0]

我们可以将数组中的数据转换为 double,在 Cython 中它是一个 cdef 类型,现在可以与之一起工作。有关更多信息以及 NumPy 教程,请访问 github.com/cython/cython/wiki/tutorials-numpy

Numba 与 Cython 的比较

Numba 是另一种让你的 Python 代码几乎成为宿主系统的本地代码的方法,通过无缝输出要在 LLVM 上运行的代码。Numba 使用以下装饰器等:

@autojit
def myFunction (): ...

Numba 还与 NumPy 集成。总的来说,这听起来很棒。与 Cython 不同,你只需将装饰器应用于纯 Python 代码,它为你做所有事情,但你可能会发现优化会更少,也不那么强大。

Numba 并没有像 Cython 那样与 C/C++ 集成。如果你想让它集成,你需要使用 外部函数接口FFI)来包装调用。你还需要在 Python 代码中以非常抽象的方式定义结构体并与 C 类型一起工作,以至于与 Cython 相比,你实际上几乎没有多少控制权。

Numba 主要由装饰器组成,例如来自 Cython 的 @locals。但最终,所有这些创建的只是即时编译的函数,具有适当的本地函数签名。由于你可以指定函数调用的类型,这应该会在调用和从函数返回数据时提供更本地的速度。我认为,与 Cython 相比,你将获得的优化将非常有限,因为你可能需要很多抽象来与本地代码通信;尽管如此,调用很多函数可能是一种更快的技术。

仅作参考,LLVM 是一个低级虚拟机;它是一个编译器开发基础设施,项目可以使用它作为即时编译器。该基础设施可以扩展以运行各种事物,例如纯 Java 字节码,甚至通过 Numba 运行 Python。它几乎可以用于任何目的,并提供了一个良好的 API 用于开发。与 GCC(一个编译时编译器基础设施)相反,GCC 在代码运行之前会提前执行大量的静态分析,LLVM 允许代码在运行时进行更改。

小贴士

如需了解更多关于 Numba 和 LLVM 的信息,您可以参考以下链接中的任何一个:

numba.pydata.org/

llvm.org/

Parakeet 和 Numba

Parakeet 是另一个与 Numba 一起工作的项目,它为使用大量嵌套循环和并行性的 Python 代码添加了非常具体的优化。与 OpenMP 类似,它真的很酷,Numba 也需要您在代码上使用注解来完成所有这些工作。缺点是您不会神奇地优化任何 Python 代码,Parakeet 所做的优化是针对非常具体的代码集。

相关链接

一些有用的参考链接:

摘要

如果您已经阅读到这里,那么您现在应该对 Cython 非常熟悉,以至于您可以使用 C 绑定将其嵌入,甚至可以使一些纯 Python 代码更加高效。我已经向您展示了如何将 Cython 应用于实际的开源项目,甚至如何使用 Twisted Web 服务器扩展原生软件!正如我在整本书中一直说的那样,这使得 C 感觉到似乎有无穷无尽的可能性来控制逻辑,或者您可以使用大量的 Python 模块来扩展系统。感谢您的阅读。

【电动汽车充电站有序充电调度的分散式优化】基于蒙特卡诺和拉格朗日的电动汽车优化调度(分时电价调度)(Matlab代码实现)内容概要:本文介绍了基于蒙特卡洛和拉格朗日方法的电动汽车充电站有序充电调度优化方案,重点在于采用分散式优化策略应对分时电价机制下的充电需求管理。通过构建数学模型,结合不确定性因素如用户充电行为和电网负荷波动,利用蒙特卡洛模拟生成大量场景,并运用拉格朗日松弛法对复杂问题进行分解求解,从而实现全局最优或近似最优的充电调度计划。该方法有效降低了电网峰值负荷压力,提升了充电站运营效率与经济效益,同时兼顾用户充电便利性。 适合人群:具备一定电力系统、优化算法和Matlab编程基础的高校研究生、科研人员及从事智能电网、电动汽车相关领域的工程技术人员。 使用场景及目标:①应用于电动汽车充电站的日常运营管理,优化充电负荷分布;②服务于城市智能交通系统规划,提升电网与交通系统的协同水平;③作为学术研究案例,用于验证分散式优化算法在复杂能源系统中的有效性。 阅读建议:建议读者结合Matlab代码实现部分,深入理解蒙特卡洛模拟与拉格朗日松弛法的具体实施步骤,重点关注场景生成、约束处理与迭代收敛过程,以便在实际项目中灵活应用与改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值