《Python高性能编程》笔记
首先理解高性能编程
高性能编程 可以被认为是通过降低开销(撰写更高效的代码)或改变操作方式(寻找更适合的算法)使得操作的代价更小。
基本计算机架构
计算机底层组件分为三部分:
计算单元
计算单元:计算机的中央部件,主要属性是其每个周期能进行的操作数量(通过每周期可以完成的指令数IPC衡量)以及每秒能完成多少个周期(通过时钟速度衡量)。
常见计算单元:GPU、CPU
提高计算速度方法:
- 提升IPC(停滞);
- 提升时钟速度(停滞);
- 超线程技术:为OS虚拟第二个CPU;
- 乱序执行:允许编译器检测出一个线性程序中某部分可以不依赖之前的工作,也就是两个工作可以以各种顺序执行或同时执行。
- 多核架构:在同一个计算单元包含多个CPU。CPU和运算速度遵循阿姆达尔定律:如果一个可以运行在多核的程序有某些执行路径必须运行在单核上,那么这些路径就会成为瓶颈导致最终速度无法通过增加更多核心来提高。
存储单元
存储单元:保存比特,可以是程序中的变量或者图片的像素。包括:主板上的寄存器、RAM以及硬盘。
常见存储单元:
- 旋转硬盘:关机下能保持长期存储。读写速度通常较慢,磁盘必须物理旋转和等待磁头移动。随机访问性能下降弹容量为TB级别。
- 固态硬盘:读写速度较快但容量为GB级别。
- RAM:用于保存应用程序的代码和数据。具有更快的访问速度且随机访问性能良好,但通常受GB级容量限制。
- L1/L2缓存:进入CPU的数据必须经过此处,读写速度极快但容量极小KB级别。
通信层
通信层本质上为总线的变种。如:RAM和L1/L2缓存之间的前端总线;硬件设备和CPU、系统内存的外部总线。
总线的主属性:速度,给定时间内可以传输的数据量的多少。
决定属性的因素:
- 总线带宽:一次可以传输多少数据。有助于矢量化(孙顺序读取)的代码。物理链路的数量决定总线的带宽。
- 总线频率:每秒能传输几次。有助于随机读取内存的代码。
Python虚拟机
影响Python性能的原因:
- 抽象性:
矢量操作变得不是直接可用(矢量化代码不是Python合法代码)。numpy可以帮助解决这个问题。
影响了任何需要为下一次计算保存L1/L2缓存中先关数据的优化(内存自动分配并在需要时释放,导致了内存碎片化)。 - 动态性以及非编译语言:代码的功能可能在运行时改变。Cython可以缓解这一个问题。
- 全局解释器锁(GIL)会影响并行代码的功能:一次仅有一个核心可以被使用。使用多进程(multiprocessing模块)或者Cython或外部函数避免这个问题。
Python的优势
- 内建了很多稳定的库。
- 封装了各类数据库。
- 封装各类网站开发框架。
- 封装计算机视觉。
- 封装各类API。
- 可以快速实现一个新主意的原型。