Python 多线程与速度
推荐
在线提问>>
问题:Python的总体性能较慢,有限的线程与孱弱的多处理能力成为其未来发展的主要障碍。
Python长期以来一直更重视编程速度,而非运行速度。考虑到很多开发者习惯于利用C或C++编写高速外部库(例如NumPy或者Numba)以执行Python下的性能密集型任务,这样的权衡似乎也没什么大不了。但问题在于,Python的开箱性能仍然落后于其它语法同样简单、但能够编译为机器码的语言,例如Nim或者Julia。
Python当中历史最悠久的性能问题之一,在于其对多核心或处理器的资源使用能力不佳。虽然Python确实具有线程功能,但却仅限于单一核心。此外,Python也会尝试通过启动其运行时的子实例以支持多处理,但是针对这些子进程结果的调度与同步往往效率不高。
解决方案:目前,还没有某一种自上而下的整体性解决方案,能够直接搞定Python的性能问题。不过,现在已经出现了一系列用于加速Python的尝试,其各自都在特定领域做出了一定改进。
下面来看例子:
改善CPython的内部行为。CPython改进带来了幅度有限但却覆盖面广泛的加速效果。例如,Python3.8的Vectorcall协议为Python对象带来了更快的调用约定。虽然改进效果不算显著,但足以带来具有可测量且可预测的性能提升,而且完全不会破坏向下兼容性;此外,现有Python应用程序可直接受益,无需任何代码重写。
改进CPython的子解释器功能。Python解释器实例的新编程接口现在可以时在各解释器之间实现优雅的数据共享,从而实现多核处理。现在,这项提案已经确定将在Python3.9中面世,相信其还将在后续版本中继续发挥重要作用。
改进多个进程之间的对象共享。Python当中的多处理机制会为每个核心启动一个新的解释器实例,用以获取最佳性能;但当多个解释器尝试对同一内存对象进行操作时,大部分性能提升都会瞬间作废。目前,以SahredMemory类以及新的pickle协议为代表的新功能,可以减少解释器之间数据传递所需要的复制或者序列化过程,从根本上消除相关性能问题。
在Python之外,也有不少外部项目带来了新的性能提升方法——但同样仅限于特定问题:
PyPy。另一种Python解释器,PyPy能够将Python即时编译为本机机器码。它在纯Python项目当中发挥出色,现在也能很好地兼容比较流行的二进制相关库——例如NumPy。但其一般更适合长期运行的服务,而非一次性应用程序。
Cython。Cython允许用户逐步将Python代码转换为C代码。该项目最初是专为科学与数值计算所设计的,但却能够在大多数场景下起效。Cython最大的缺点在于语法,其使用了独有的语法设置,且转换只能单向进行。Cython最适合处理“热点”部分代码,这种有针对性的优化方式往往比应用程序整体优化要更合理、也更可行。
Numba。Numba的即时编译功能可以面向选定功能将Python代码编译为机器码。与Cython类似,Numba同样主要用于科学计算,其比较适合就地运行而非对代码进行重新发布。
Mypyc。Mypyc项目目前仍在开发当中,其希望将带有mypy类型注释的Python代码转换为C代码。Mypyc很有前途,因为其使用到Python中的众多原生类型,但目前距离生产应用还有很长的路要走。
经过优化的Python发行版。某些第三方Python版本(例如英特尔的Python发行版)拥有可充分发挥英特尔处理器扩展(例如AVX512)优势的数学与统计库。需要注意的是,尽管其能够显著加快特定数学函数的执行速度,但却无法实现全面的速度提升。
有经验的Python程序员一定还会提到全局解释器锁(GIL)的问题,其负责对指向对象的访问进行序列化,以确保不同线程不会彼此影响到对方的工作负载。从理论上讲,放弃GIL可以提高性能。然而,无GILPython基本上丧失了向下兼容能力(特别是在PythonC扩展方面)。因此到目前为止,所有移除GIL的尝试要么已经走进死胡同,要么反而降低了Python的性能。
目前另一个正在推进的Python计划有望解决不少速度方面的问题,即重构Python内部的CAPI实现。众长远来看,提升API集的有序程度可以带来诸多性能改进:重新设计或者剔除GIL、提供可实现强大即时编译的hook、在解释器实例之间使用更好的数据联合方法等等。
以上内容为大家介绍了Python多线程与速度,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注IT培训机构:千锋教育。http://www.mobiletrain.org/