写点什么

论 Python 语言的三大短板与解决办法

  • 2019-08-22
  • 本文字数:3554 字

    阅读完需:约 12 分钟

论 Python 语言的三大短板与解决办法

多年以来,Python 语言一直受到性能、应用程序打包以及项目管理三大问题的困扰。好在,解决方案即将到来。


虽然 Python 诞生距今已经有 30 年左右,但就在过去几年当中,其受欢迎程度开始快速提升并达到旷古烁今的地步。当下,唯有 Java 及 C 等顶尖高手能够与之匹敌。另外,Python 的普及程度超越了传统编程语言,目前在教学与学术研究当中成为最优编程方法、理想的软件开发起点以及几乎一切技术堆栈的重要组成部分。


遗憾的是,旺盛的人气也放大了 Python 语言的固有缺陷。与其优点一样,Python 也有着不少天生顽疾——性能、应用程序打包与交付,以及项目管理困难,一直是支持者心中永远的痛。虽然这些并不算什么致命缺陷,只能说是 Python 普及道路上的一点障碍;但随着 Julia、Nim、Rust 以及 Go 等其他竞争语言的崛起,解决这些问题已经成为 Python 的燃眉之急。


在本文中,我们将探讨 Python 程序员面对的三大主要挑战,以及 Python 自身、第三方 Python 工具以及库开发者们尝试解决这些挑战的具体方法。

Python 多线程与速度

问题:Python 的总体性能较慢,有限的线程与孱弱的多处理能力成为其未来发展的主要障碍。


Python 长期以来一直更重视编程速度,而非运行速度。考虑到很多开发者习惯于利用 C 或 C++编写高速外部库(例如 NumPy 或者 Numba)以执行 Python 下的性能密集型任务,这样的权衡似乎也没什么大不了。但问题在于,Python 的开箱性能仍然落后于其它语法同样简单、但能够编译为机器码的语言,例如 Nim 或者 Julia。


Python 当中历史最悠久的性能问题之一,在于其对多核心或处理器的资源使用能力不佳。虽然 Python 确实具有线程功能,但却仅限于单一核心。此外,Python 也会尝试通过启动其运行时的子实例以支持多处理,但是针对这些子进程结果的调度与同步往往效率不高。


解决方案:目前,还没有某一种自上而下的整体性解决方案,能够直接搞定 Python 的性能问题。不过,现在已经出现了一系列用于加速 Python 的尝试,其各自都在特定领域做出了一定改进。


下面来看例子:


  • 改善 CPython 的内部行为。 CPython 改进带来了幅度有限但却覆盖面广泛的加速效果。例如,Python 3.8 的 Vectorcall 协议为 Python 对象带来了更快的调用约定。虽然改进效果不算显著,但足以带来具有可测量且可预测的性能提升,而且完全不会破坏向下兼容性;此外,现有 Python 应用程序可直接受益,无需任何代码重写。

  • 改进 CPython 的子解释器功能。 Python 解释器实例的新编程接口现在可以时在各解释器之间实现优雅的数据共享,从而实现多核处理。现在,这项提案已经确定将在 Python 3.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 可以提高性能。然而,无 GIL Python 基本上丧失了向下兼容能力(特别是在 Python C 扩展方面)。因此到目前为止,所有移除 GIL 的尝试要么已经走进死胡同,要么反而降低了 Python 的性能。


目前另一个正在推进的 Python 计划有望解决不少速度方面的问题,即重构 Python 内部的 C API 实现。众长远来看,提升 API 集的有序程度可以带来诸多性能改进:重新设计或者剔除 GIL、提供可实现强大即时编译的 hook、在解释器实例之间使用更好的数据联合方法等等。

Python 打包与独立可执行文件

问题:即使是在 30 年之后,Python 仍然没能拿到理想的方法,用以将程序或脚本转换为自打包可执行文件,并轻松部署在多种平台之上。


虽然这一目标已经有办法实现,但依靠的主要是第三方工具,而非 Python 的原生功能——此外,其使用难度也不太友好。


最具知名且最受支持的当数PyInstaller,它能够打包多种广受喜爱的高人气第三方扩展,例如 NumPy。不过PyInstaller必须与这些第三方扩展手动保持同步,而这在 Python 的庞大生态系统中无疑是一项艰巨的任务。此外,PyInstaller会生成超大的应用程序包,因为其中捆绑有程序 import 语句中所要求的全部内容,而且并不确定在运行时究竟会用到哪些组件。此外,PyInstaller也无法实现跨平台应用程序打包;我们必须在目标部署平台上进行包创建。


解决方案: 我对 PyInstaller 抱有充分的尊重,但我们可能还需要一套 Python 原生解决方案——无论是内置形式,还是通过标准库提供。它应当允许开发人员以独立二进制文件的形式将 Python 应用程序打包并交付至各类常见的平台。理想情况下,这款内置的打包器应该利用运行时代码覆盖率信息确保仅打包所需的库(而非所有内容),并能够自动与其余 Python 库保持同步。


目前还没有这样的解决方案存在,但关于如何构建此类工具的提示倒是所在多有。PyOxidizer 项目使用 Rust 语言生成能够嵌入 Python 的二进制文件,并将此作为创建独立 Python 应用程序的一种方法。虽然该项目尚处于起步阶段,距离成为完整的应用程序交付方案还有很长的路要走,但这足以证明 Python 生态系统之外的成果也许会成为解决挑战的关键。

Python 安装、软件包管理与项目管理

问题: 有些使用体验太过复杂——对,说的就是为专业级 Python 项目设置工作区、目录结构与基本架构;管理与项目相关的环境、软件包及依赖项;以可重复方式重新分配项目来源;并一次又一次不断进行这个过程。


Rust 与 Go 这两种语言,在初始设计阶段就强调提供一种单一且规范的项目设置方式,并允许开发者在整个生命周期之内对其进行轻松管理。Rust 与 Go 开发人员虽然因此牺牲掉了一定程度的灵活性,但却换来了良好的一致性、可预测性以及可管理性。


Python 提供的安装、软件包以及项目管理工具与方法,随着时间推移而不断积压,并成为 30 年发展周期中的一笔重大负担。其中有用于软件包管理的 pip、用于创建虚拟环境的 venv/virtualenv、用于元管理的 virtualenvwrapper 与 Pipenv、用于生成项目依赖性的 pip-tools、以及用于创建 Python 代码发行版的 distutils 与 setuptools 等。此外,还有负责定义项目其它部分的 setup.py、requirements.txt、setup.cfg、MANIFEST.in 以及 Pipfile 等等。


解决方案: 同样的,我们需要取代这如同一团乱麻的工具与流程大杂烩,由 Python 核心开发团队拿出一套规范性的解决方案,同时确保其能够优雅地迁移一切利用现有方法开发出的项目。当然,这是个很难解决的挑战,但随着 Python 语言变得越来越重要,我们必须努力让它成为一款易于上手、维护简单、一致性强且友好舒适的编程工具。


目前这方面工作已经有所进展。根据 PEP 518 提案,Python 的 build 依赖项被合并为 pyproject.toml 文件格式。而像poetry 这样的第三方工具虽然只能打包现有工具,但已经体现出一体化管理产品的样貌。随着时间的推移,其中一种解决方案也许会脱颖而出、受到整个社区的关注,并成为客观层面甚至是范式性的处理标准。


原文链接:


https://www.infoworld.com/article/3429565/3-major-python-shortcomingsand-their-solutions.html?upd=1566265910128


2019-08-22 10:507445

评论 1 条评论

发布
用户头像
与其想尽办法去处理这些 Python 问题,还不如选择另一个更适合的语言,成本更低。
2019-08-22 11:42
回复
没有更多了
发现更多内容

融云获 CSDN 技术影响力之星评选「年度技术品牌奖」

融云 RongCloud

兴业+民生上岸面试经验分享

暖蓝笔记

3月程序媛福利 3月月更

智能问答机器人

DS小龙哥

智能问答机器人 3月月更 智能对话机器人

网络协议之:socket协议详解之Unix domain Socket

程序那些事

socket Netty 程序那些事 3月月更

TPC TiKV:Hackathon 中最硬核项目是如何炼成的?| TPC 战队访谈

PingCAP

sql TiDB

iuap助力澳洋集团打造主数据管理平台

用友BIP

用友 用友iuap

Java基础重要面试题(二)

逆锋起笔

java面试 java基础 3月月更

中小企业如何搭建在线客服中心?

小炮

测试2

Journeyman

手绘流程图,教你WSL2与Docker容器无缝互相迁移

华为云开发者联盟

Docker 容器 WSL2 迁移

ICT的圣杯(二):数字生活的另类想象

脑极体

Open Harmony移植:build lite编译构建过程

华为云开发者联盟

编译 OpenHarmony build lite 芯片开发板

mark: Docker 容器镜像删除

webrtc developer

面试突击31:什么是守护线程?它和用户线程有什么区别?

王磊

java面试

写给后端开发工程师的H5前端开发知识

得物技术

前端 Web 可视化 后端开发 交互

全面解析云智慧数据中心统一运管解决方案

云智慧AIOps社区

安全 运维自动化 数据处理 数据可视化 监控工具

Nacos源码分析(一)之线程池的巧妙设计,可以薅到自己的项目里

刘祥

SpringCloud Alibaba

微信外H5跳转小程序——<JumpApp/>组件(vue项目)

CRMEB

测试1

Journeyman

融云猿桌派备忘录,那些被程序员 Pick 的工作方式

融云 RongCloud

程序员 IM

实用机器学习笔记二十八:迁移学习

打工人!

学习笔记 迁移学习 机器学习算法 3月月更

一文详解Redis键过期策略

华为云开发者联盟

redis key 惰性删除 定期删除 键过期

虎符交易所Hoo研究院:元宇宙中的Decentraland是什么?

区块链前沿News

元宇宙 Hoo虎符 虎符研究院

PendingIntent重定向:一种针对安卓系统和流行App的通用提权方法——BlackHat EU 2021议题详解 (下)

安第斯智能云

安全 安卓

阿里智能运维实践|阿里巴巴DevOps实践指南

阿里云云效

云计算 阿里云 DevOps 云原生 智能运维

对微博系统中“微博评论”的高性能高可用计算架构的一点思考

晨亮

「架构实战营」

图解|从根儿上理解MySQL的索引

蝉沐风

MySQL 索引 B+树

从读写角度,带你了解数仓的IO基本框架

华为云开发者联盟

io GaussDB(DWS) IO框架 行存 列存

【CAD】入门系列完

謓泽

3月月更

使用bds搭建我的世界官方基岩版服务器(windows篇)

Daimon

这些DDD"术语"你知道吗?

idonkeyliu

DDD

论 Python 语言的三大短板与解决办法_语言 & 开发_Serdar Yegulalp_InfoQ精选文章