写点什么

加载速度提升 15%,关于 Python 启动加速探索与实践的解析

  • 2022-12-27
    北京
  • 本文字数:1474 字

    阅读完需:约 5 分钟

加载速度提升 15%,关于 Python 启动加速探索与实践的解析

在 PyCon China 2022 大会上,龙蜥社区开发者严懿宸分享了主题为《Python 启动加速的探索与实践》的技术演讲。本次演讲,作者将从 CPython 社区相关工作、本方案的设计及实现,以及业务层面的集成等方面进行介绍。本文为本次演讲内容整理。

一、Python 启动速度简析


首先从一个 Python 3 中空解释器启动时间的好事分析开始。我们可以看到,主要的耗时都和 Python 包加载有关。



其中,CPU 时间中包加载占据了 30% 左右的时间;而 37% 的等待时间中,磁盘 IO 等花费的时间也和包加载有较大的关联。


熟悉 Python 机制的朋友大概知道,Python 中加载一个包首先会搜索对应的 pyc 文件,这是一种序列化的字节码格式。找到之后会对其进行反序列化,并执行其中的代码。如对应的 pyc 文件不存在,会重新编译 py 文件得到字节码,并序列化为 pyc 文件持久化保存。我们优化的主要目标主要集中在加载包这个过程,希望能够至少免去每次查找、读取、反序列化的开销。



Python3.10 为例,这里是使用 python 解释器启动一个空语句的所需时间,同时使用了 -Ximporttime 打印出过程中加载每一个包的耗时。可以粗略地看到,包加载时间大约占了总时间的 30% 左右。我们发现这种情况和 Java 虚拟机类似。在 Java 中,Java 会首先将 Java 源代码编译为 Java 字节码,随后由 Java 命令执行。


我们知道 Java 的优势并不包括启动速度,这种流程也是原因之一。那么 Java 如何部分解决这个问题呢?

二、PyCDS (代码对象共享)设计与实现



Java 中有一个叫做 CDS/AppCDS 的机制,通过将 Java 字节码和一些辅助数据持久化保存,在后续启动时使用 mmap 加载,节约了磁盘 IO 和解析验证 class 文件的开销。


很自然的想法是,如果我们希望在 Python 中使用类似的技术,目标应该是 Python 字节码



Python 默认从 py 文件导入模块的逻辑如上图左边所示,首先根据制定的名字获取对应的规则,随后尝试寻找 pyc 文件或重新编译。最后,使用 exec 命令利用代码和一个空 dict 来创建模块,并加入 runtime。


我们做的事情可以简化为右侧逻辑。同样根据包名,尝试从 mmap 中加载。如果成功,那么同样的 codeobject 也可以用于初始化。


这样做有什么直接的障碍?


可以看到,Python 中代码对象的 C 数据结构大致如图,包括 consts、string、bytes 等 Python 数据类型。



以使用到的 codeobject 作为 root,将涉及的数据序列化存储到内存映射中。


在这一步,最直接的问题是内存随机化机制。在处理 code object 中的 Python 对象时,每个 Python 对象头中都保存着指向当前进程中对应类型信息的指针。Runtime 通过这个指针判断该对象在 Python 中的类型。


以 PyCode_Type 为例,如果不做处理,这里会丢失类型信息(红色 offset)。


为了解决这个问题,在我们创建的镜像文件中会保存涉及的对象指针。在加载时动态 patch 相关的指针。


在整个过程中涉及的 Python 类型包括


1. 常量(bool/None/ellipsis)

2. 字面量(float/complex)

3. 需要额外分配的变量(long/bytes/str)

4. container(tuple/frozenset)


对于常量和字面量,在内存映射中分配好空间后直接赋值即可保存;对于后两种,需要模拟 Python 中变量初始化的逻辑,创建合适的内存大小并写入对应位置。同时,对于非常量的类型,还需要对内存映射中的引用计数额外赋值,防止意外触发 Python 中的回收。


以上就是本项目的大致内容,另外关于项目的具体用法请前往 PyCDS 项目主页或我们在龙蜥实验室上的课程查看,链接见下:

龙蜥实验室课程:

https://lab.openanolis.cn/#/apply/chapters?courseId=117

 PyCDS 主页:

https://github.com/alibaba/code-data-share-for-python

2022-12-27 18:253759

评论

发布
暂无评论
发现更多内容

云堡垒机优点简单说明-行云管家

行云管家

网络安全 堡垒机 云堡垒机

工业5.0:为何是下一个10年的制造业关键性变革方向?

PreMaint

工业4.0 智能制造

AirServer正式版Mac7.2.7屏幕软件下载

茶色酒

AirServer AirServer2023

软件测试/测试开发 | 一文搞定 Appium 环境配置

测试人

软件测试 自动化测试 测试开发 appium app自动化测试

分布式系统-CAP理论

非晓为骁

分布式系统 CAP理论 分布式理论

pip安装'torch'出现PackageNotFoundError报错解决办法

Geek_7ubdnf

Python

新一代云原生日志架构 - Loggie的设计与实践

网易数帆

开源 云原生 日志 Loggie 企业号 1 月 PK 榜

4种LED显示屏箱体连接方式

Dylan

LED LED显示屏 户外LED显示屏

解决高基数难题,云原生时序数据库 TDengine 3.0 荣获 IT168 2022 年度技术卓越奖

TDengine

数据库 tdengine 时序数据库

关于局域网中的攻击溯源问题

郑州埃文科技

IP溯源 局域网

Redux与前端表格施展“组合拳”,实现大屏展示应用的交互增强

葡萄城技术团队

平安健康 Dubbo 3 升级、迁移和验证之路

阿里巴巴中间件

阿里云 云原生 dubbo

为测试管理正名,华为云CodeArts TestPlan的守护之道

华为云开发者联盟

云计算 测试 华为云 华为CodeArts 企业号 1 月 PK 榜

基于 APISIX 的服务网格方案 Amesh 积极开发中!

API7.ai 技术团队

Service Mesh Service Mesh 服务网格 服务网格 APISIX

TiDB 中标杭州银行核心系统数据库项目

PingCAP

#TiDB

【带你读论文】向量表征经典之DeepWalk

华为云开发者联盟

人工智能 华为云 企业号 1 月 PK 榜 向量表征

Sentinel Go-毫秒级统计数据结构揭秘

阿里巴巴中间件

Go 阿里云 云原生 Sentienl

Github 标星 41.6K!Alibaba内网Java性能调优实战(全彩小册开源)

架构师之道

Java 程序员 架构 面试

阿里云Imagine Computing创新技术大赛决赛启幕!

阿里云CloudImagine

云计算 阿里云 视频云 边缘云

SAP系统在企业内部控制方面有哪些独到之处?

SAP虾客

报表 SAP系统 业财一体化 change history

数据的不确定性及可视化方法

搞大屏的小北

2022年个人云盘行业发展分析和厂商实力洞察

易观分析

用户 私有云盘

云图说 | 勒索病毒防治解决方案

华为云开发者联盟

云计算 后端 华为云 企业号 1 月 PK 榜

Databend 借助对象存储帮你实现降本增效

Databend

手把手教您在PyCharm中连接云端资源进行代码调试

华为云开发者联盟

人工智能 华为云 企业号 1 月 PK 榜

数据可视化图表系列解析——漏斗图

Data 探险实验室

数据分析 可视化 数据可视化 图表 可视化数据

NFTScan 与 Afflux 孵化器达成战略合作伙伴,共同促进 Web3 生态发展!

NFT Research

NFT

SEO 已死,LLMO 万岁

Jina AI

人工智能 搜索引擎 SEO 谷歌 ChatGPT

南京市等级测评机构有哪些?哪里可以查到?

行云管家

南京 等级测评机构

秒云荣获四川省创新型中小企业认定

MIAOYUN

创新型中小企业 2022创新型中小企业 四川省创新型中小企业 科技型中小企业

会议室怎么添加预约功能?快速解决会议室使用效率问题

天天预约

小程序 SaaS 线上预约 会议室 预约工具

加载速度提升 15%,关于 Python 启动加速探索与实践的解析_文化 & 方法_严懿宸_InfoQ精选文章