新闻详情

新闻详情

首页 / 资讯中心 / 详情

深入理解 Python 虚拟机:字典(dict)的优化

发布时间:2026/10/1 7:28:08来源:尧图网络
深入理解 Python 虚拟机:字典(dict)的优化
1. 引言Python 的字典dict是这门语言最核心、最常用的数据结构之一。无论是模块的命名空间、对象的属性查找还是函数的关键字参数传递背后都离不开字典的身影。正因如此CPython 对字典的实现进行了多轮深度优化使其在保持灵活性的同时也能拥有出色的性能。本文将深入 CPython 源码剖析字典从早期版本到现代版本Python 3.6的演进历程重点讲解紧凑布局compact layout、哈希表结构、冲突解决策略以及**键共享key-sharing**等关键优化技术帮助你真正理解 Python 字典为什么快、快在哪里。2. 字典的基础哈希表字典本质上是一张哈希表hash table。它通过哈希函数将键key映射到一个固定大小的数组索引上从而实现平均 O(1) 的查找、插入和删除。2.1 哈希函数与哈希值Python 中每个对象都可以通过hash()函数获取一个整数哈希值。对于整数哈希值就是它本身取模后对于字符串CPython 使用 SipHash 算法计算对于自定义对象则调用其__hash__方法。hash(hello)-1182516015910hash(42)42需要注意的是哈希值并不是直接作为数组下标使用的而是需要经过一步**取模mod**运算映射到哈希表的容量范围内。2.2 冲突与解决当两个不同的键计算出相同的数组索引时就发生了哈希冲突collision。CPython 采用**开放寻址法open addressing**来解决冲突当某个槽位已被占用时会按照一定的探测序列probe sequence继续向后查找直到找到空槽或匹配的键。# 伪代码开放寻址的探测过程deffind_slot(table,key):indexhash(key)%len(table)whiletable[index]isnotNoneandtable[index].key!key:index(index1)%len(table)# 线性探测returnindexCPython 实际使用的探测策略比简单的线性探测更精细它基于哈希值的高位信息来生成探测步长从而减少聚集clustering现象。3. 传统实现分离式存储Python 3.5 及以前在 Python 3.5 及更早版本中字典的底层结构是一个单一的 entries 数组每个 entry 同时存储哈希值、键和值typedefstruct{Py_hash_t me_hash;// 哈希值PyObject*me_key;// 键PyObject*me_value;// 值}PyDictEntry;整个字典就是这样一个 entry 数组加上一些元信息容量、已用数量等。3.1 传统实现的问题这种实现有一个明显的缺点内存利用率低。为了保证查找效率哈希表的负载因子load factor通常维持在 2/3 以下也就是说有大约 1/3 的槽位是空的。在传统实现中这些空槽位同样占用完整的 entry 空间每个 entry 24 字节造成了大量内存浪费。此外遍历字典时需要扫描整个数组跳过所有空槽位效率也不高。4. 现代实现紧凑布局Python 3.6Python 3.6 引入了一项革命性的优化——紧凑字典compact dict由 INADA Naoki 提出。这一设计将索引与数据分离从根本上解决了内存浪费问题。4.1 双数组结构现代字典由两个数组组成索引数组indices一个int数组长度等于哈希表的容量通常是 2 的幂存储的是 entry 在 entries 数组中的下标。entries 数组一个紧凑的 entry 数组只包含实际存在的键值对按插入顺序排列。typedefstruct{PyObject*me_key;// 键PyObject*me_value;// 值Py_hash_t me_hash;// 哈希值}PyDictKeyEntry;4.2 查找过程查找时先通过哈希值定位到 indices 数组中的某个槽位取出对应的 entry 下标再到 entries 数组中访问真正的键值对# 伪代码紧凑字典的查找deflookup(d,key):idxhash(key)%len(d.indices)entry_indexd.indices[idx]ifentry_index-1:# 空槽returnNoneentryd.entries[entry_index]ifentry.keykey:returnentry.value# 冲突则继续探测4.3 内存节省由于 indices 数组只存储整数下标每个 1~8 字节视容量而定而 entries 数组只存储实际存在的键值对空槽位不再占用完整的 entry 空间。对于一个小字典如 8 个键值对内存占用可以从传统实现的数百字节降低到几十字节节省幅度可达数倍。4.4 保持插入顺序紧凑布局的另一个副产品是字典现在保持插入顺序。因为 entries 数组按插入顺序追加遍历时只需顺序扫描 entries 数组即可无需跳过空槽。这一特性在 Python 3.7 中被正式写入语言规范成为所有 Python 实现必须遵守的行为。d{b:1,a:2,c:3}list(d.keys())[b,a,c]# 保持插入顺序5. 键共享字典Key-Sharing Dict在 Python 3.3 中CPython 引入了键共享字典key-sharing dict专门用于优化对象属性存储。5.1 问题背景每个 Python 对象都有一个__dict__属性字典用于存储实例属性。如果每个实例都拥有一份独立的、完整的字典结构那么对于大量同类的实例对象会浪费大量内存——因为它们的键属性名几乎完全相同只有值不同。5.2 共享机制键共享字典的核心思想是将键属性名和哈希值提取出来放到一个共享的 keys 对象中所有同类的实例共用这一份 keys每个实例只保存自己的 values 数组。typedefstruct{Py_ssize_t dk_refcnt;// 引用计数Py_ssize_t dk_size;// 容量PyDictKeyEntry*dk_entries;// 共享的键和哈希值// ...}PyDictKeysObject;实例对象的结构变为typedefstruct{PyObject_HEAD PyDictKeysObject*ma_keys;// 指向共享的 keysPyObject**ma_values;// 本实例的值数组}PyDictObject;5.3 收益对于大量同类实例例如 ORM 模型、数据类实例键共享字典可以显著减少内存占用。假设有 10000 个实例每个有 5 个属性传统实现需要 10000 份完整的字典结构而键共享实现只需要 1 份 keys 10000 份 values 数组内存节省非常可观。classPoint:def__init__(self,x,y):self.xx self.yy# 大量 Point 实例共享同一份 keysx, ypoints[Point(i,i*2)foriinrange(10000)]5.4 注意事项键共享字典有一个限制一旦某个实例的字典被直接修改例如添加了新的键该实例就会脱离共享转为独立的完整字典。因此在性能敏感的场景中应尽量避免对实例的__dict__进行动态增删键的操作。6. 其他优化细节6.1 哈希值缓存对于字符串键CPython 会缓存其哈希值。字符串对象内部有一个字段用于存储计算过的哈希值这样同一个字符串在多次作为字典键查找时无需重复计算哈希。typedefstruct{PyObject_HEAD Py_ssize_t ob_shash;// 缓存的哈希值-1 表示未计算// ...}PyUnicodeObject;6.2 小字典的快速路径CPython 对容量较小的字典如 1~5 个键值对提供了专门的快速路径避免通用查找逻辑的开销。这些小型字典在创建时直接使用栈上分配的固定大小数组进一步减少内存分配次数。6.3 调整大小策略当字典的负载因子超过 2/3 时字典会进行扩容通常将容量翻倍。扩容时indices 数组会重新分配但 entries 数组中的键值对可以原地保留只需重新计算每个 entry 在 indices 中的映射关系这比传统实现中整体搬迁 entry 数组要高效得多。7. 性能对比与实测为了直观感受这些优化带来的收益我们可以做一个简单的内存对比实验importsys# 传统方式大量独立小字典dicts[{a:i,b:i1,c:i2}foriinrange(10000)]print(sys.getsizeof(dicts[0]))# 单个字典的大小# 键共享方式大量同类实例classObj:def__init__(self,a,b,c):self.aa self.bb self.cc objs[Obj(i,i1,i2)foriinrange(10000)]print(sys.getsizeof(objs[0].__dict__))# 单个实例字典的大小在 Python 3.11 中运行上述代码你会发现单个实例的__dict__大小远小于独立字典的大小这正是键共享优化的直接体现。8. 总结Python 字典的优化之路是 CPython 在内存效率与访问速度之间不断权衡的缩影紧凑布局将索引与数据分离大幅降低内存占用并顺带实现了插入有序键共享字典针对对象属性存储场景让大量同类实例共享键结构节省海量内存哈希值缓存与小字典快速路径等细节优化让常见操作更加高效。理解这些底层机制不仅能帮助你写出更高效的代码例如避免破坏键共享、合理预估字典容量也能让你在阅读 CPython 源码时更加游刃有余。字典虽小却凝聚了 Python 设计者数十年的智慧。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

阿里云CPFS全栈自研高性能存储:AI训练成本降低69%的工程实践 2026/10/1 8:32:49

阿里云CPFS全栈自研高性能存储:AI训练成本降低69%的工程实践

1. 从"存储吃掉一半预算"说起:CPFS到底在解决什么问题做过大模型训练的人都有一个共同体会:算力账单虽然贵,但真正让人肉疼的往往是存储。一个千亿参数级别的模型,训练数据集动辄几十TB到上百TB,checkpoint每…

阅读更多 →
2026年亚太工业微生物培养基蛋白胨理化分析与选型指南 2026/10/1 8:32:49

2026年亚太工业微生物培养基蛋白胨理化分析与选型指南

文章目录一、工业微生物培养基配制中蛋白胨的营养屏障二、107213颗粒型酪蛋白胨物理形态与理化常数三、高溶解度与低粉尘颗粒化加工的物理化学机制四、环境潮湿条件与加样称量中时间因子的控制五、品牌内酪蛋白胨与大豆蛋白胨物理规格段落对比六、苛养微生物发酵与食品药性检测…

阅读更多 →
DeepSeek弹性计算精读:从vLLM部署到API接入的工程实践指南 2026/10/1 8:32:48

DeepSeek弹性计算精读:从vLLM部署到API接入的工程实践指南

拿到“DeepSeek Elastic Compute (DSec)精读”这个标题,我最开始以为又是哪个新出的模型命名,真正去翻了一圈资料才发现,它说的不是某个具体的模型,而是一整套把DeepSeek这类开源模型变成“可弹性伸缩的推理服务”的架构思路和工具…

阅读更多 →
AI生成法律文书选哪家国内推荐优质甄选服务覆盖全国 2026/10/1 8:32:42

AI生成法律文书选哪家国内推荐优质甄选服务覆盖全国

随着法律需求的普及和数字化工具的发展,AI生成法律文书已经成为很多律师、法务和普通用户提升办事效率的首选,不过市面上相关服务商质量参差不齐,很多用户不知道该怎么选到靠谱的服务。 行业普遍痛点与市场需求 当前法律AI文书服务行业普遍存…

阅读更多 →
零代码搭建AI-Agent实战:从入门到进阶的完整指南 2026/10/1 8:32:42

零代码搭建AI-Agent实战:从入门到进阶的完整指南

1. 为什么“零代码”是AI-Agent落地的第一站1.1 从“写代码”到“搭积木”的思维转变很多人第一次听到“AI-Agent”这个词,脑子里浮现的都是满屏的Python代码、复杂的API调用、各种向量数据库和模型部署。我刚开始接触的时候也是这个反应,觉得这东西门槛…

阅读更多 →
摆脱论文困扰!2026年实打实好用的专业AI论文平台 2026/10/1 8:32:36

摆脱论文困扰!2026年实打实好用的专业AI论文平台

2026年AI论文写作工具已从“单点辅助”升级为全流程学术智能解决方案,核心评价维度涵盖文献真实性、格式合规性、长文本逻辑、查重降重、AIGC合规等关键指标。本次测评覆盖6款主流工具,涵盖中英文、全流程与专项功能、免费与付费版本,帮你高效…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉