尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
CPython frozenset 构造性能优化:避免复制,让 frozenset(frozenset) 直接复用原对象
CPython frozenset 构造性能优化避免复制让 frozenset(frozenset) 直接复用原对象【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython本篇技术指南围绕 CPython 的一条核心运行时改进展开frozenset对象在构造阶段避免不必要的元素复制。该改动落在 CPython 内置类型层Core and Builtins读者读完后将理解frozenset的完整构造链路参数校验 → vectorcall → 幂等复用 → 哈希表填充 → GC 跟踪策略并能基于 Objects/setobject.c 中的源码证据判断什么场景下frozenset()是零拷贝的、什么场景下仍会发生全量插入。一、这次优化改了什么对应的变更记录位于 Misc/NEWS.d/next/Core_and_Builtins/2026-05-18-17-16-51.gh-issue-150027.sJgLvd.rst全文只有两行Improve performance offrozensetobjects by avoiding copies during construction.提升frozenset对象性能避免在构造期间产生复制。一句话概括当frozenset()的参数本身就是一个精确的frozenset实例时CPython 不再创建新对象并逐项复制元素而是直接返回原对象的引用。这在 Objects/setobject.c 的make_new_frozenset中实现static PyObject * make_new_frozenset(PyTypeObject *type, PyObject *iterable) { if (type ! PyFrozenSet_Type) { return make_new_set(type, iterable); } if (iterable ! NULL PyFrozenSet_CheckExact(iterable)) { /* frozenset(f) is idempotent */ return Py_NewRef(iterable); } PyObject *obj make_new_set(type, iterable); if (obj ! NULL) { _PyFrozenSet_MaybeUntrack(obj); } return obj; }见 Objects/setobject.c。三个关键细节只对精确类型生效PyFrozenSet_CheckExact(iterable)要求参数必须是frozenset本身而不是它的子类。若参数是frozenset子类实例走的是通用构造路径保证子类的__init__/初始化语义不被短路。Py_NewRef而非返回原指针直接Py_INCREF原对象并返回把引用计数交给调用方符合 CPython 对象所有权约定——调用方拿到返回值后负责释放原对象的存活期因此自然延长。幂等性idempotent是安全前提frozenset(f)的结果在语义上与原对象完全一致——相同的元素、相同的类型且frozenset不可变复用不会引入任何可观察的行为差异。这正是这条优化可以成立的理论依据。二、完整的 frozenset 构造链路从 Python 层的frozenset(x)调用到对象返回实际调用链如下参数入口两种形态经典tp_new路径frozenset_newObjects/setobject.c。它先拒绝关键字参数_PyArg_NoKeywords(frozenset, kwds)报错文本固定为frozenset再用PyArg_UnpackTuple解出 0 到 1 个位置参数。更快的 vectorcall 路径frozenset_vectorcallObjects/setobject.c由类型对象的.tp_vectorcall槽注册见 Objects/setobject.c 附近的PyFrozenSet_Type定义。它跳过tp_new的元对象分发直接校验位置参数个数后进入make_new_frozenset。幂等短路即上文第一节的PyFrozenSet_CheckExact分支。通用构造路径make_new_frozenset落到make_new_set(type, iterable)后者由make_new_set_untrackedObjects/setobject.c完成实体分配so (PySetObject *)_PyType_AllocNoTrack(type, 0); ... so-fill 0; so-used 0; so-mask PySet_MINSIZE - 1; so-table so-smalltable; // 先用对象内嵌的小表 so-hash -1; so-finger 0; so-weakreflist NULL; if (iterable ! NULL) { if (set_update_local(so, iterable)) { ... } }注意注释里写明的设计约束Objects/setobject.cBuild a set/frozenset left GC-untracked; the caller must_PyObject_GC_TRACK()it once fully built, so a half-built set is never exposed during filling.——对象在填充完成前不进入 GC 跟踪避免其他线程看到只填了一半的 set填充成功后才由make_new_set调用_PyObject_GC_TRACK。GC 卸载优化对象建成后make_new_frozenset还会调用_PyFrozenSet_MaybeUntrackObjects/setobject.c。该函数来自 gh-140232 的相关改进遍历 frozenset 的全部元素若没有任何元素是被 GC 跟踪的如全部是 int、str 等不可跟踪对象就把整个 frozenset 从 GC 跟踪列表中移除减少后续 GC 周期的扫描开销。子类实例不参与卸载因为子类可能引入引用环。这条链路说明本次优化是在最坏情况路径之前加了一道最廉价的短路判断——先做类型精确检查O(1)命中即一次Py_INCREF返回未命中才付出分配 逐元素哈希插入 哈希表扩容的成本。三、复制路径到底贵在哪set_update_local 的分发逻辑理解短路收益需要看清被短路掉的那条路径有多重。填充入口是set_update_localObjects/setobject.c它对源对象做了四档分发源对象类型走的路径说明set/frozenset任意集合set_merge_lock_held直接遍历源集合的哈希表逐个set_add_entry可批量预扩容精确dictset_update_dict_lock_held借_PyDict_Next迭代键值对见 Objects/setobject.c可预知PyDict_GET_SIZE并据此一次性扩容Objects/setobject.cfrozendict内部类型同上无需锁frozendict 不可变直接迭代其他可迭代对象set_update_iterable_lock_heldPyObject_GetIter 逐项PyIter_Nextset_add_key最慢对集合源走的是set_merge_lock_held需要Py_BEGIN_CRITICAL_SECTION获取源集合临界区、逐项复制键并处理哈希表扩容set.update这类对已公开对象的更新走set_update_internalObjects/setobject.c还多了一层对so与other的双重临界区保护Py_BEGIN_CRITICAL_SECTION2并对自更新so is other做了直接返回的短路。也就是说优化前frozenset(f)要经历分配新对象 → 复制内嵌表或扩容 → 逐项set_add_entry含哈希查找、冲突处理→ 全程持有源集合临界区 → GC 跟踪。优化后只剩一次引用计数递增。对把 frozenset 当缓存键/常量反复包装的场景例如每层递归都frozenset(prev_keys)这是数量级的差异。四、set为何没有同样待遇对照代码可以明确这次优化的边界set_newObjects/setobject.c只做make_new_set(type, NULL)set(x)若传入集合会完整复制元素——这是刻意的set可变复用同一对象会让两个独立的 set 共享同一份可改数据直接破坏语义。而frozenset不可变 值语义frozenset(f) is f在精确类型下成为可能注意是可能返回的是Py_NewRef引用同一对象因此is恒成立但 frozenset 子类、dict 源、list 源等仍会新建对象。五、如何验证这一行为在任意使用当前仓库构建的 CPython 中可直接观察f frozenset({1, 2, 3}) f2 frozenset(f) print(f2 is f) # True —— 精确类型下直接复用原对象 print(frozenset(frozenset()) is frozenset()) # False —— 两次独立构造 class Sub(frozenset): pass s Sub([1, 2]) print(frozenset(s) is s) # False —— 子类不走幂等短路仍会新建预期结果精确frozenset的二次包装与源对象同一身份子类实例则仍触发完整构造。相关测试入口在 Lib/test/test_set.py其中包含对 frozenset 构造、比较、哈希等行为的成组覆盖回归验证时可优先运行该文件。六、对使用方的实际含义写代码无需改变该优化完全透明frozenset(x)的调用方式、异常行为均不变只是参数恰好是 frozenset这一常见路径变快。性能敏感场景受益以 frozenset 做字典键的嵌套结构如递归解析、DAG 去重、类型参数组合缓存中频繁的frozenset(existing)包装调用现在接近零成本。不要依赖is做逻辑判断虽然精确类型下frozenset(f) is f成立但这属于实现细节层面的幂等性保证仅用于性能不应把它当作 API 契约来写业务逻辑类型上仍是返回一个引用计数递增后的 frozenset。free-threading 环境同样适用填充路径全程使用临界区critical section保护源集合Objects/setobject.c而幂等短路路径不持有任何锁在无 GIL 构建下收益更为直接。七、小结这条两行的 NEWS 背后是 CPython 内置类型层一次典型的识别并消除冗余拷贝优化在make_new_frozenset中利用frozenset的不可变性与精确类型检查将frozenset(f)从分配 全量元素复制 GC 登记降级为一次Py_NewRef。配合既有的 GC 卸载机制_PyFrozenSet_MaybeUntrack与 vectorcall 直达入口frozenset 构造在小集合高频调用的场景下开销被压到最低。阅读 Objects/setobject.c 中make_new_frozenset、set_update_local、set_merge_lock_held三个函数的对照关系是理解 CPython 集合构造快慢分层的最佳切口。【免费下载链接】cpythonThe Python programming language项目地址: https://gitcode.com/GitHub_Trending/cp/cpython创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

深入理解Go的panic、defer与recover:运行时协作机制与工程实践

深入理解Go的panic、defer与recover:运行时协作机制与工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/10 7:19:33
hermes-agent实践:为大模型装上工具调用的手脚

hermes-agent实践:为大模型装上工具调用的手脚

如果你让大模型帮你“查一下服务器日志”,大概率会得到一段shell命令,然后贴心提示你“请自己在终端里执行”——那一刻你会意识到,大模型什么都不缺,缺的是一双能干活的手和脚。hermes-agent 就是我为了解决这个问题做的Agent项目…

📅 2026/9/10 7:14:32
Spring Boot整合JdbcTemplate:告别MyBatis繁琐,轻量数据访问实战

Spring Boot整合JdbcTemplate:告别MyBatis繁琐,轻量数据访问实战

Spring Boot 整合 JdbcTemplate,绕开 MyBatis 的繁琐也能把数据访问写得明明白白先聊聊我自己的选型经历。早几年做项目,团队一上来就上 MyBatis,生成 XML、配置 mapper、管理 resultMap,一套流程下来,小项目光搭架子就…

📅 2026/9/10 7:14:32
MORE NEWS

更多资讯

📰

Postmortem: [Incident Title]

Postmortem: [Incident Title] 【免费下载链接】agents Multi-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity 项目地址: https://gitcode.com/GitHub_Trending/agents24/agents Date: 2024-01…

📰

5分钟用Semgrep静态代码分析找出硬编码密钥:新手快速上手指南

5分钟用Semgrep静态代码分析找出硬编码密钥:新手快速上手指南 【免费下载链接】semgrep Lightweight static analysis for many languages. Find bug variants with patterns that look like source code. 项目地址: https://gitcode.com/GitHub_Trending/se/semg…

📰

AI搜索优化完全指南:从传统SEO到AEO/GEO的实战方法论

1. 先搞清楚:AI搜索优化和传统SEO到底差在哪这两年做网站流量的朋友应该都有个明显感觉:以前那套“堆关键词、买外链、刷收录”的打法,越来越不灵了。原因很简单——用户的搜索入口变了。以前大家习惯打开搜索引擎,输入关键词&…

📰

数据迁移工具全解析:从原理选型到DataX与CDC实战

1. 数据迁移在数据工程中的真实定位1.1 迁移不是搬数据,而是搬语义干数据工程这些年,我最大的感受是:业务方催得最急的往往不是模型多精准,而是数据什么时候能搬完。所谓大数据领域的数据工程,绕不开一个基础动作——数…

📰

Magnitude不是CLI工具:词向量检索库的真相与实战

1. “magnitude”不是命令行工具,而是被误读的模型服务基础设施组件最近在多个技术社区和开发者群聊里,频繁看到有人搜索“magnitude CLI”“magnitude install”“unable to locate the magnitude binary”,甚至混搭出“magnitude cli infer…

📰

AI代理安全加固:用E2B沙箱和Firecracker微虚拟机隔离OpenClaw风险

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬