- 内容提要
- 前言
- 作者简介
- 封面简介
- 第1章 理解高性能 Python
- 第2章 通过性能分析找到瓶颈
- 2.1 高效地分析性能
- 2.2 Julia 集合的介绍
- 2.3 计算完整的 Julia 集合
- 2.4 计时的简单方法——打印和修饰
- 2.5 用 UNIX 的 time 命令进行简单的计时
- 2.6 使用 cProfile 模块
- 2.7 用 runsnakerun 对 cProfile 的输出进行可视化
- 2.8 用 line_profiler 进行逐行分析
- 2.9 用 memory_profiler 诊断内存的用量
- 2.10 用 heapy 调查堆上的对象
- 2.11 用 dowser 实时画出变量的实例
- 2.12 用 dis 模块检查 CPython 字节码
- 2.13 在优化期间进行单元测试保持代码的正确性
- 2.14 确保性能分析成功的策略
- 2.15 小结
- 第3章 列表和元组
- 第4章 字典和集合
- 第5章 迭代器和生成器
- 第6章 矩阵和矢量计算
- 第7章 编译成 C
- 第8章 并发
- 第9章 multiprocessing 模块
- 第10章 集群和工作队列
- 第11章 使用更少的 RAM
- 第12章 现场教训
7.10 Pythran
Pythran是一个把Python转换成C++的编译器,作用于包含对部分numpy支持的Python子集。它表现得有点像Numba和Cython——你注解一个函数的参数,接着它接管进一步的类型注解和代码特化。它利用了矢量化可能性和基于OpenMP的并行化可能性。它只用Python2.7运行。
Pythran的一个很有趣的特点是它会意图自动发现并行化的机会(例如,如果你正使用一个map),并把它转换成并行代码,而不需要你额外的工作量。你也能用pragma omp来声明并行区域,在这方面,感觉它很类似于Cython对OpenMP的支持。
在幕后,Pythran会企图把通常的Python代码和numpy代码很激进地编译成速度很快的C++代码——甚至比Cython的结果更快。你应该注意到这个项目是年轻的,你可能会遇到错误;你也应该注意到开发团队很友好并倾向于在几小时内修正错误。
再看一下例6-9中的扩散方程。我们已经把例程中的计算部分抽取出来放到一个独立模块中,这样它就能被编译成一个二进制库。Pythran的一个良好特点就是我们不产生与Python不兼容的代码。回想起Cython,我们不得不用注解的Python来创建 .pyx文件,这样就不能被Python直接运行了。使用Pythran时,我们只需添加一行注释来让Pythran编译器识别。这意味着如果我们删除了生成的.so编译模块,我们就能单独用Python来运行我们的代码——这对调试很有利。
在例7-16中,你可以看见我们更早期的传热方程的例子。evolve函数有一行注释来为函数注解类型信息(因为它是注释,所以如果你不用Pythran运行,Python只会忽略注释)。当Pythran运行时,它看到那行注释并且通过每一个相关的函数来传播类型信息(很像我们见到的Shed Skin)。
例7-16 添加一行注释去注解evolve()的入口点
import numpy as np def laplacian(grid): return np.roll(grid, +1, 0) + np.roll(grid, -1, 0) + np.roll(grid, +1, 1) + np.roll(grid, -1, 1) - 4 * grid #pythran export evolve(float64[][], float) def evolve(grid, dt, D=1): return grid + dt * D * laplacian(grid)
我们可以用pythran diffusion_numpy.py来编译这个模块,会输出diffusion_numpy.so。从一个测试函数中,我们可以导入这个新模块并且调用evolve。在Ian的笔记本上,不用Pythran的话,这个函数在一个8192×2192的网格上运行了3.8秒。用了Pythran后降低到1.5秒。显然,如果Pythran支持你需要的函数的话,它就能够得到令人印象深刻的性能提升,而几乎无须做什么工作。
速度提升的原因是Pythran有它自己的roll函数版本,功能更少——因此它能编译成复杂度更低的运行可能更快的代码。这也意味着它比numpy版本(Pythran的作者说明Pythran只实现了部分numpy)的灵活度要低,但是当它工作时,能够胜出我们所见到的其他工具的运行结果。
现在让我们把相同的技术应用于Julia的展开数学表达式的例子中。只是给calculate_z添加一行注解,我们就能把运行时间降低到0.29秒——比Cython的结果慢一点点。在外循环的前面添加一行OpenMP声明后把执行时间降低到0.1秒,距离Cython的最佳OpenMP结果已经不远。注解的代码在例7-17中可见。
例7-17 得到OpenMP支持的注解Pythran的calculate_z
#pythran export calculate_z(int, complex[], complex[], int[]) def calculate_z(maxiter, zs, cs, output): #omp parallel for schedule(guided) for i in range(len(zs)):
迄今为止我们所见的技术都涉及使用常规CPyhon解释器之外的编译器。现在让我们看一下PyPy,它提供了一个全新的解释器。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论