- 内容提要
- 前言
- 作者简介
- 封面简介
- 第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.12 什么时候使用每种工具
如果你正工作于数值处理的项目,那么这些技术中的每一种可能都对你有用。表7-1总结了主要选项。
如果你的问题适用于可支持函数的严格范围内,Pythran大概在numpy问题上提供了最佳的性能提升,却花费最少的工作量。它也提供了一些简单的OpenMP并行项,这也是一个相对年轻的项目。
表7-1 可选的编译器总结
Cython
Shed Skin
Numba
Pythran
PyPy
成熟度
Y
Y
_
_
Y
广泛使用性
Y
_
_
_
_
支持Numpy
Y
_
Y
Y
_
没有间断的代码改动
_
Y
Y
Y
Y
需要有C的知识
Y
_
_
_
_
支持OpenMP
Y
_
Y
Y
Y
Numba可能提供了快速的性能提升,而几乎不需要什么工作量,但是它也会有在你的代码上可能不会工作得很好的限制。这也是一个相对年轻的项目。
Cython可能为最广泛的问题集提供了最好的结果,但是它的确需要更多的工作量和交额外的“支持税”,这要归因于它混合使用了Python和C注解。
如果你不使用numpy或其他难以移植的C扩展,PyPy是一个强力的选择。
如果你想要编译成C并且不使用numpy或其他外部库,Shed Skin可能是有用的。
如果你正在部署一个生产工具,那么你可能想要坚持使用理解良好的工具——Cython应该是你的主要选择,你可能想要查阅在12.2节。PyPy也被用于产品设置(看看12.5节)。
如果你工作于少量的数值处理需求,注意Cython的缓存接口接受arrary.array矩阵——这是一个把一块数据传给Cython的简单方法,可用来做快速的数值处理而不用添加numpy作为项目依赖。
整体而言,Pythran和Numba是年轻但是很有前景的项目,而Cython十分成熟。PyPy到现在被视为相对成熟,并且应该一定要有长期的过程来评估。
在2014年的一堂Ian的课上,一个有能力的学生实现了Julia算法的C版本,并且失望地看到它执行得比他的Cython版本要慢。他透露在64位机器上使用了32位浮点数——这要比在64位机器上使用64位双精度数运行得慢。尽管该学生是一个好的C程序员,但他不知道这会牵涉到执行速度上的代价。他改变了代码,他的C版本代码尽管明显比自动生成的Cython版本要短小得多,却跑出了大概一样的速度。编写原始的C版本,对比速度,并且想出修正方案,这一系列行为要比一上来就用Cython花费更长的时间。
这只是个趣闻轶事,我们没有建议说Cython会生成最好的代码,并且胜任的C程序员也能够想出怎样让他们的代码比Cython生成的版本运行得更快。然而,值得注意的是,假想手写C代码会比由Python转换成的代码更快也不靠谱。你一定要始终做基准测试并且使用证据来做决定。C编译器很擅长把代码转换为相对高效的机器码,而Python很擅长让你用更易于理解的语言来表达你的问题——明智地结合这两种力量。
7.12.1 其他即将出现的项目
PyData编译器页列出了一系列高性能编译工具。Theano是一个更高级的语言,允许使用高维数组上的数学操作符表达式。它与numpy紧密结合,并且能为CPU和GPU导出编译过的代码。有趣的是,它已经受到了深度学习AI社区的青睐。Parakeet集中于涉及密集numpy数组的编译运算,使用Python的子集。它也支持GPU。
PyViennaCL是一个Python绑定到ViennaCL的数值计算和线性代数库。它使用numpy,支持GPU和CPU。ViennaCL用C++编写,为CUDA、OpenCL和OpenMP生成代码。它支持密集和稀疏的线性代数运算、BLAS和求解器。
Nuitka是一个以替代通常的CPython解释器为目标的Python编译器,具有创建编译过的可执行程序的选项。它支持Python2.7的全部,尽管在我们的测试中,它没有为我们普通的Python数值测试产生任何明显的性能提升。
Pyston是该领域最新的加入者。它使用了LLVM编译器,被Dropbox支持。由于缺少对扩展模块的支持,它可能遭受与PyPy所面临的同样的问题,但是有项目计划去解决这个问题。如果这个问题得不到解决,对numpy的支持就不现实。
在我们的社区里,我们很幸运拥有各种各样可选的编译器。虽然它们都各有取舍,但它们也提供了许多能力,这样复杂的项目就能充分利用CPU和多核架构的力量。
7.12.2 一个图像处理单元(GPU)的注意点
GPU在当前是个性感的技术,我们选择了把涉及它们的话题拖后直到至少下一版。这是因为该领域在飞速变化,很可能我们现在所说的所有东西到我们读到它时已经改变了。关键的是,它不只是让你改变所写的代码行,而是随着架构的演进,你可能要彻底改变解决问题的方式。
Ian工作于一个物理学问题,使用Python和PyCUDA,用了一年的NVIDIA GTX 480 GPU。到年底为止驾驭了GPU的全部能力,并且系统比在双核机器上运行相同的函数快了整整25倍。双核的变体用C写成,使用了一个并行库,为了数据处理,GPU的变体大部分由PyCUDA所包装的CUDA的C所表达。很快在那之后,GTX 5xx系列的GPU问世了,许多应用于4xx系列的优化就发生了改变。大概耗费一年的工作最终被放弃了,还是倾向于运行在CPU上的更易于维护的C的解决方案。
这是一个孤立的例子,但是它强调了写底层CUDA(或OpenCL)代码的危险。在GPU之上的提供了更高级功能的库可能已得到了广泛使用(例如,提供了图像分析或视频转码接口的库),我们规劝你去考虑这些库,而不是去直接为GPU编码。
以为你管理GPU为目标的项目包括Numba、Parakeet和Theano。
7.12.3 一个对未来编译器项目的展望
在当前的可选的编译器之中,我们已经有一些强大的技术组件。就个人而言,我们想要看到Shed Skin的注解引擎变得广泛适用,这样它就能和其他工具一起工作——例如,当学用Cython(尤其当使用numpy时)时,产生一个兼容Cython的输出来让学习曲线变平滑。Cython是成熟的并且紧密集成入Python和numpy,如果学习曲线和对支持的需求不那么可畏,那么更多人会使用它。
更长期的愿望就是看到一些类似Numba和PyPy的解决方案在常规Python代码和numpy代码上都提供JIT的解决方案。当前没有一个解决方案可用,一个解决了这个问题的工具将会是替代我们当前都在使用的常规CPython解释器的强有力的竞争者,而不需要开发者修改他们的代码。
友善的竞争和对新思路的巨大市场真的会让我们的生态系统变成一个富足的地方。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论