澳门新葡亰平台官网Python性能鸡汤《二》【转载】

by admin on 2020年3月26日

特别是,Antonio
专注于加速在用户的本地音乐收藏中寻找歌曲/音乐副本的过程。最初的代码通过
Python 实现,后来变成了经过优化的 C++ 代码。令人惊讶的是,优化调整过的
C++ 代码要比 Python 快得多 ——
如果你希望了解作者为实现这个结果所做出的调整,以及所采取的各种步骤带来的影响,不妨看看作者所写的博客。

第二部分

他没有用 C++ 重写整个程序,而是使用了 Boost.Python 库,该库使得 C++ 和
Python 代码之间可进行无缝的操作。从这时开始,Antonio 开始编写相关的 C++
代码。特别是,他专注于 C++ 17 并使用了线程。进一步提升性能的操作是调整
C++ 的编译器标记(compiler flags),并将 GCC 从 7.3 版本切换到 8.1
版本。

    有益的提醒,静态编译的代码仍然重要. 仅例举几例,
Chrome,Firefox,MySQL,MS Office 和
Photoshop都是高度优化的软件,我们每天都在使用.
Python作为解析语言,很明显不适合.
不能单靠Python来满足那些性能是首要指示的领域.
这就是为什么Python支持让你接触底层裸机基础设施的原因,
将更繁重的工作代理给更快的语言如C.
这高性能计算和嵌入式编程中是关键的功能.
Python性能鸡汤第一部分讨论了怎样高效的使用Python. 在第二部分,
我们將涉及监控和扩展Python.

从我使用 C++
代码完成了不同编译器的基准测试到现在,已经有一段时间了。由于我最近发布了
ETL 项目的 1.1
版(一个具有表达式模板的优化矩阵/向量计算库),所以我决定使用它作为我的基准测试的基版本。它是一个带有大量模板的
C++ 14 库。我要编译完整的测试套件(124
个测试用例)。这是直接在最新版本(1.1)的代码上完成的。我将在调试模式下编译一次,并在
release_debug(release + debug
符号和断言)下进行一次编译,并记录每个编译器的执行时间。该测试将使用支持
ETL
中的每个选项的配置进行编译,以此计算最大的编译时间。每次编译都使用四个线程(make
-j4)。
我还做了一些基准测试,以了解每个编译器生成的代码间的运行时的性能差异。基准测试将编译为发布模式,并记录其编译时间。

长话短说,“作者的最后一次代码提交也最后一次提升了速度,达到
7998 倍 ——
36680首/秒(对比速度),并可在13秒内完全处理完一个1000首歌曲的音乐集。”有关更详细具体的技术细节请查看作者原博客,也可以访问他的 Bard
音乐管理器项目以了解更多。

  1. 首先, 拒绝调优诱惑
       调优给你的代码增加复杂性. 集成其它语言之前, 请检查下面的列表.
    如果你的算法是“足够好”, 优化就没那么迫切了.
    1) 你做了性能测试报告吗?
    2) 你能减少硬盘的 I/O 访问吗?
    3) 你能减少网络 I/O 访问吗?
    4) 你能升级硬件吗?
    5) 你是为其它开发者编译库吗?
    澳门新葡亰平台官网,6)你的第三方库软件是最新版吗?

  2. 使用工具监控代码, 而不是直觉
        速度的问题可能很微妙, 所以不要依赖于直觉. 感谢 “cprofiles” 模块,
    通过简单的运行你就可以监控Python代码 ,如下:
    “python -m cProfile myprogram.py”
    我们写了个测试程序. 基于黑盒监控. 这里的瓶颈是 “very_slow()”
    函数调用. 我们还可以看到 “fast()” 和 “slow()”都被调用200次. 这意味着,
    如果我们可以改善 “fast()” 和 “slow()” 函数,
    我们可以获得全面的性能提升. cprofiles 模块也可以在运行时导入.
    这对于检查长时间运行的进程非常有用.

  3. 审查时间复杂度
        控制以后, 提供一个基本的算法性能分析. 恒定时间是理想值.
    对数时间复度是稳定的. 阶乘复杂度很难扩展.

O(1) -> O(lg n) -> O(n lg n) -> O(n^2) -> O(n^3) ->
O(n^k) -> O(k^n) -> O(n!)

 

  1. 使用第三方包

   有很多为Python设计的高性能的第三方库和工具.
下面是一些有用的加速包的简短列表.

1) NumPy: 一个开源的相当于MatLab的包

2) SciPy: 另一个数值处理库

3) GPULib: 使用GPUs加速代码

4) PyPy: 使用 just-in-time 编译器优化Python代码

5) Cython: 將Python优码转成C

6)ShedSkin: 將Python代码转成C++

  1. 使用multiprocessing模块实现真正的并发

       因为GIL会序列化线程,
Python中的多线程不能在多核机器和集群中加速.
因此Python提供了multiprocessing模块, 可以派生额外的进程代替线程,
跳出GIL的限制. 此外, 你也可以在外部C代码中结合该建议,
使得程序更快.注意, 进程的开销通常比线程昂贵,
因为线程自动共享内存地址空间和文件描述符. 意味着,
创建进程比创建线程会花费更多, 也可能花费更多内存.
这点在你计算使用多处理器时要牢记.

  1. 本地代码

      好了, 现在你决定为了性能使用本地代码. 在标准的ctypes模块中,
你可以直接加载已编程的二进制库(.dll 或 .so文件)到Python中,
无需担心编写C/C++代码或构建依赖. 例如,
我们可以写个程序加载libc来生成随机数.然而,
绑定ctypes的开销是非轻量级的.
你可以认为ctypes是一个粘合操作系库函数或者硬件设备驱动的胶水. 有几个如
SWIG, Cython和Boost 此类Python直接植入的库的调用比ctypes开销要低.
Python支持面向对象特性, 如类和继承. 正如我们看到的例子,
我们可以保留常规的C++代码, 稍后导入. 这里的主要工作是编写一个包装器
(行 10~18).

我将测试以下编译器:

最后作者也就这次优化总结了一些心得:

总结:

  • GCC-4.9.4
  • GCC-5.4.0
  • GCC-6.3.0
  • GCC-7.1.0
  • clang-3.9.1
  • clang-4.0.1
  • zapcc-1.0 (商业版,基于 clang-5.0 主分支)
  • 花一些时间思考如何优化代码 —— 这件事十分值得开发者去做

  • 如果你使用 C++ 并能够使用现代编译器,那么请使用 C++
    17,它可以让你更有效地编写更好/更优雅的代码。Lambdas、结构化绑定、constexpr
    等特性真的值得花时间阅读它们

  • 允许编译器为你做的事情。,它可以对你的代码进行优化而无需你的任何努力

  • 尽可能少地复制/移动数据。这个操作很慢,很多时候只需要在开发之前考虑一下数据结构就可以避免这个操作

  • 尽可能使用线程

  • 最后,可能也是最重要的:量化一切指标。你不能改进你无法量化的东西(嗯,技术上你可以,但你肯定不知道)

我希望这些Python建议能让你成为一个更好的开发者. 最后, 我需要指出,
追求性能极限是一个有趣的游戏, 而过度优化就会变成嘲弄了.
虽然Python授予你与C接口无缝集成的能力,
你必须问自己你花数小时的艰辛优化工作用户是否买帐. 另一方面,
牺牲代码的可维护性换取几毫秒的提升是否值得.
团队中的成员常常会感谢你编写了简洁的代码. 尽量贴近Python的方式,
因为人生苦短. 🙂

所有这些都是直接使用 Portage(Gentoo
软件包管理器)安装的,除了从源代码安装的 clang-4.0.1 以及没有 Gentoo
软件包的 zapcc。由于 Gentoo 上的 clang
包不支持多进程,所以我不得不从源代码中安装一个版本,从包管理器中安装另一个版本。这也是我测试较少版本的
clang 的原因,更实用点。

参考 https://www.phoronix.com/

为了实现这些测试的目标,所有编译器都使用了完全相同的选项。通常,我在
clang 上使用比 GCC 更多不同的选项(主要是考虑到在 clang
上更严格的向量化选项)。这可能不会使得每个编译器达到最佳性能,但可以对使用默认优化级别的输出之间进行比较。以下是使用的主要选项:

  • 调试模式下: -g
  • 发布+调试模式下: -g -O2
  • 发布模式下: -g -O3 -DNDEBUG -fomit-frame-pointer

每种情况都启用了许多警告,ETL 选项也是一样的。

所有的测试结果都是运行在 Intel Core i7-2600(Sandy Bridge …)@ 3.4GHz
上的 Gentoo 机器上收集的,该机器具有 4 核和 8 线程、12G 的 RAM 和一个
SSD。我尽可能地从干扰项中分离出基准数据,并且我的基准代码是相当健全的,但是有些结果可能并不完全准确。此外,一些基准测试是在使用多线程,这可能会增加一些干扰和不可预测性。当我对测试结果不太确定时,我会多次运行基准测试以对此确认,并且总体而言,我对结果很有信心。

编译时间

让我们从编译器自身的性能结果开始:

澳门新葡亰平台官网 1

注: 在 Release_Debug 和 Benchmark,我对 zapcc 只使用了三个线程, 因为
12Go 的内存对于四个线程并不足够。

不同的编译器之间有一些非常重要的区别。总地来说,clang-4.0.1
是迄今为止调试模式下最快的免费编译器。然而,当测试代码被添加优化选项加以编译,clang
就落后了。在调试模式和发布模式下,clang-4.0.1 比 clang-3.9.1
快得多,这一点令人印象深刻。在这一点上 clang 团队干得不错!这些优化,使得
clang-4.0.1 在发布模式下几乎与 gcc-7.1 平分秋色。对于 GCC
来说,优化的成本似乎一直在显著地上升。然而, GCC 7.1
似乎使得优化加快,也使得标准编译快了许多。如果我们考虑
zapcc,这是调试模式下最快的编译器,但它的速度在发布模式下比几个 gcc
版本要慢。

总地来说,我对 clang-4.0.1
的性能印象深刻,它看起来真快!在不久的将来,我一定会用这个新版本做更多的测试。看到
g++-7.1 的编译速度确实快于
gcc-6.3,也同样令人欣慰。然而,对优化而言,最快的 gcc 版本仍然是
gcc-4.9.4 ,这已经是一个对 C++ 标准低支持的老版本。

运行时性能

现在来看看生成的代码的质量。对于一些基准测试,我已经包含了两个版本的算法。
std 是最简单的算法(原始版),vec
是手工向量化和优化的实现版本。所有的测试都是在单精度浮点上完成的。

点乘

运行的第一个基准是计算两个向量之间的点积。让我们先看看原始版的性能:

澳门新葡亰平台官网 2

不同的编译器之间的差异不是很大。基于 clang
的编译器似乎是生成速度最快代码的编译器。有趣的是,gcc-6.3
似乎在大数据量的容器中有一个很大的性能衰减,但在 gcc-7.1 中已经解决了。

澳门新葡亰平台官网 3

如果我们查看优化版本的结果,其中差异更小。同样,基于 clang
的编译器生成的可执行文件是最快的,但紧随其后的是 gcc,除了 gcc-6.3
之外,我们仍然可以看到与之前相同的性能衰退。

Logistic Sigmoid

下一个测试是检查 sigmoid
操作的性能。在这种情况下,库的评估者将尝试使用并行化和向量化来计算。让我们看看不同编译器的开销如何:

澳门新葡亰平台官网 4

有趣的是,我们可以看到,gcc-7.1 在少量数据时是最快的,而 clang-4.0
最适合生成较大数据时的代码。然而,除了最大的向量大小,差异并不是很明显。显然,zapcc(或
clang-5.0)有一个回归,因为它比 clang-4.0 慢,并与 clang-3.9 相同速度。

Y = Alpha * X + Y (axpy)

第三个基准是著名的 axpy(y = alpha * x +
y)。这是完全由库中的表达式模板决定的,没有使用特定的算法。我们来看看结果:

澳门新葡亰平台官网 5

即使是最大的
vector,一旦向量化和并行化之后,这也是一个非常快速的操作。以这种速度,观察到的一些差异可能不是很重要。再次,基于
clang 的版本是这段代码中最快的版本,但差异还是很小。在 gcc-7.1
中似乎还有一点回归,但这也是相当小的。

矩阵间的乘法 (GEMM)

下一个基准测试是测试 Matrix-Matrix 乘法的性能,这是在 BLAS 命名中被称为
GEMM
的操作。在这种情况下,我们同时测试原始的和优化的向量化实现。为了节省一些横向空间,我把表分成两部分。

澳门新葡亰平台官网 6

这一次,不同编译器之间的性能差异非常大。clang
编译器现在是大幅度领先,其中 clang-4.0
是他们中最快的(也有不错的提升幅度)。事实上,clang-4.0.1
生成代码,平均比最好的 GCC 编译器生成的代码速度快两倍。非常有趣的是,从
GCC-5.4 开始,我们可以看到一个巨大的性能衰退,而且这种衰退还在 GCC-7.1
中。事实上,测试版本中最好的 GCC 版本依然是 GCC-4.9.4。Clang 真的在编译
GEMM 代码方面做得很好。

澳门新葡亰平台官网 7

至于优化的版本,这两大家族是相反的。的确,GCC 在这方面做的工作比 clang
要好,尽管差距没有以前那么大了,但还是值得注意。我们还是可以观察到 GCC
版本中的一个小回归,因为 4.9 版本依然是最快的。至于 clang 版本,似乎
clang-5.0 (在 zapcc 中使用)在这个例子中有了很多的性能改进。

在这个例子中矩阵相乘,它是非常令人印象深刻的,优化与非优化代码在性能上差异非常巨大。并且,令人印象深刻的是,每种类型的编译器都有它们的长处,clang
看起来更适合处理没优化过的代码,而 GCC 更适合处理向量化的代码。

【编辑推荐】

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图