workerd 中的 Pyodide:把 Python 运行时“编译进” JavaScript 引擎的构建与加载机制

发布时间:2026/9/16 19:37:33

workerd 中的 Pyodide:把 Python 运行时“编译进” JavaScript 引擎的构建与加载机制 workerd 中的 Pyodide把 Python 运行时“编译进” JavaScript 引擎的构建与加载机制【免费下载链接】workerdThe JavaScript / Wasm runtime that powers Cloudflare Workers项目地址: https://gitcode.com/GitHub_Trending/wo/workerd本文围绕 src/pyodide/README.md 展开讲解 workerd驱动 Cloudflare Workers 的 JavaScript / Wasm 运行时是如何将 Pyodide 打包成 bundle 嵌入自身、如何裁剪 Pyodide 的包加载机制、以及“为什么要这么做、接下来要怎么做”的设计权衡并结合 src/pyodide/BUILD.bazel、src/workerd/api/pyodide/pyodide.h 与 samples/pyodide/ 的源码和示例说明从构建产物到运行时加载的完整链路以及如何在本地跑通一个 Python Worker。一、这个目录在做什么README 开篇给出的定位非常直接src/pyodide/存放“生成被构建进 workerd 的 Pyodide bundle”所需的全部代码。它由三部分协作完成src/pyodide/目录本身包含生成 bundle 的构建代码Bazel 规则、打包工具、内嵌的 TypeScript/Python 运行时模块。从源码结构看该目录还承担运行时层的角色——AGENTS.md 将其描述为 “Python Workers runtime layer”其中的模块会以pyodide-internal:*的 BUILTIN 模块形式注册。build/BUILD.pyodide目前只做一件事——exports_files(glob([pyodide/*]))即把 Pyodide 官方发布产物下载后落盘到build/pyodide/暴露给 workerd 的构建系统。src/workerd/api/pyodide/pyodide.hC 侧的接入点在开启相应 compatibility flag 时把 Pyodide bundle 加入 module registry让 V8 isolate 能够加载。README 同时说明了一个重要前提该功能需要experimental兼容性开关才能启用。而在当前仓库的示例 samples/pyodide/config.capnp 中实际使用的是专门的 Python Workers 开关const mainWorker :Workerd.Worker ( modules [ (name worker.py, pythonModule embed ./worker.py), ], compatibilityDate 2023-12-18, compatibilityFlags [python_workers, python_workers_20250116], );python_workers是功能总开关python_workers_20250116是绑定到特定 Python 快照发布release的开关。这一点与 src/pyodide/pyodide_extra.capnp 中的 schema 对应每个PythonSnapshotRelease常量携带pyodide版本号、packages包 bundle 日期、backport回退计数、baselineSnapshotHash基线内存快照的 sha256以及flagName/fieldName等字段——也就是说“开关 → 特定 Pyodide/Python 快照版本”的映射是在构建期生成进 capnp schema 的而不是运行时动态决定的。二、为什么要把 Pyodide 编译进 workerd设计权衡README 专门用一节标题提出疑问“Do we really want to be compiling this stuff into workerd?”我们真的想把这套东西编译进 workerd 吗并给出了明确的结论与理由。这一节值得完整理解因为它决定了当前架构的取舍升级主版本风险高。Pyodide 每升一个大版本都可能带来脚本层面的破坏每个 Pyodide 版本都绑定了一个特定的 Python 版本和一份特定的包 lockfile锁定所有包的版本与依赖信息。任何在新 Python 或新版包上会出问题的脚本都会在升级时一起出问题。因此必须允许用户固定pin旧版本。而在开始支持多个 Pyodide 版本之前合理的做法是在运行时动态获取用户所需的 Pyodide 版本而不是把一大堆“可能用不上”的代码都塞进二进制里撑大体积。同理用户使用的 Python 包将来也大概率需要动态获取。现状是“最快跑通”的方案。README 明确承认“The present approach is just the fastest way to get something working.”当前方案只是最快能跑起来的方式。换言之把 Pyodide 静态编入 workerd 是一个有意识的、暂时的权衡先保证功能可用再逐步演进到多版本 动态下载。仓库中的构建配置印证了这一演进方向src/pyodide/BUILD.bazel 顶部从 build/python_metadata.bzl 加载BUNDLE_VERSION_INFO并用BUNDLE_VERSION_INFO[development][real_pyodide_version]作为开发版本名通过alias生成pyodide.capnp.bin、pyodide等重定向目标——“多版本并存、按版本选择 bundle”的框架已经搭好只是当前还只有一个开发版本在生效。三、Pyodide bundle 到底装了什么README 的 “Whats happening here?” 一节说明了 Pyodide 官方发行物的组成以及 workerd 只取其中一部分Pyodide 的发行物包括主“emscripten 二进制”pyodide.asm.js与pyodide.asm.wasm加载器pyodide.jsPython Pyodide 标准库python_stdlib.zip包 lockfilepyodide-lock.json包含发布中构建的所有包的版本与依赖信息……其他东西。workerd 目前只取pyodide.asm.js、pyodide.asm.wasm和python_stdlib.zip并且通过不配置 lockfile 彻底禁用了包加载——因为 workerd 最终需要自己的包管理机制而且这个机制“很可能发生在配置阶段configuration time”。关于加载器的替换README 提到src/pyodide/python.js作为pyodide.js的简化替代它去掉了包加载器和大部分配置但增加了**内存快照memory snapshot**支持。团队希望把内存快照支持上游回 Pyodide但“维护一个自己的精简加载器未来大概率仍有价值”。需要指出的是README 中写的python.js在当前的仓库结构里已经演进为 src/pyodide/internal/python.ts——从 AGENTS.md 的组件表可以确认internal/python.ts是“核心桥Emscripten 初始化、Pyodide 引导、快照编排”并配套internal/snapshot.ts基线/专用快照的收集与恢复、internal/setupPackages.ts与internal/loadPackage.ts包挂载、sys.path、vendor 目录等模块。3.1 版本与 lockfile 在仓库中的落地“每个 Pyodide 版本绑定一份 lockfile”这一约束在仓库中体现得非常具体src/pyodide/python-lock/ 目录按“日期 修订号”命名提交了两份 checked-in 的包 lockfilepyodide-lock_20240829.4.json2024-08-29 发布第 4 次修订pyodide-lock_20250808.json2025-08-08 发布BUILD.bazel 通过exports_files(glob([python-lock/*.json]))将它们导出注释说明其用途是供pyodidemodule extensionbuild/deps/dep_pyodide.bzl读取以便下载 stdlib wheels——“同一 Pyodide 版本 不同包修订”的双坐标pyodide版本号 ×packages日期与上面PythonSnapshotReleaseschema 的字段一一对应也解释了为什么 lockfile 文件名要同时携带日期和修订号。3.2 构建产物如何被“嵌入”helpers.bzl 中的pyodide_extra()、pyodide_static()、python_bundles()三个宏是 bundle 构建的核心python_packages.capnp 定义 stdlib wheel 文件的嵌入 schemapack_python_packages.py 是一个构建期工具把 stdlib wheels 解包、编码进一个PythonPackagescapnp 消息最终嵌入 Pyodide bundle这一流程在 BUILD.bazel 的注释中被直接写明。输出的pyodide.capnp.bin是一个自描述的 capnp 消息对于无法本地构建它的 runner例如交叉编译仓库还提供了一个 alias pyodide.capnp.bin_cross在prebuilt_binaries_arm64配置下直接重定向到预编译产物bin.arm64/tmp/pyodide/pyodide.capnp.bin.aarch64-linux-gnu。C 侧的 pyodide.h 则定义了运行时读取这些嵌入数据的整套接口可以按职责分为几组组件职责PyodideBundleManager按版本存取 Pyodide bundle 数据setPyodideBundleData/getPyodideBundlebundle 以进程级kj::Directory/消息形式持有EmbeddedPackagesReader从 bundle 中定位嵌入的python_packages数据模块getFiles()一次性返回文件布局每个条目携带指向“已解压字节”的ReadOnlyBuffer读取器避免逐文件的 JS↔C 往返拷贝PyodideMetadataReader向 Python 运行时暴露 worker 元数据主模块、模块文件内容getNames/getSizes/read、Pyodide/包版本、lockfile、内存快照hasMemorySnapshot/readMemorySnapshot、compat flags 等ArtifactBundlerMemorySnapshotResult验证器validator在部署验证时收集“初始化完成后的 Python 解释器状态”快照用于加速冷启动区分“基线/通用快照”与“专用快照”DiskCache仅本地开发用把跨 workerd 重启获取的 wheel 等数据落到磁盘缓存SimplePythonLimiterPython 专属的启动期 CPU 时限beginStartup/finishStartup之间超限即抛 TypeError头文件注释中注明目前采用“启动结束后再检查”的事后策略WorkerFatalReporter把 fatal error 上报给 request observerRuntime Analytics此外pyodide.h 末尾声明了 bundle 完整性校验接口computePyodideBundleIntegrity计算 subresource-integrity 风格的sha256-base644校验和verifyPyodideBundleIntegrity在运行时校验下载的 Pyodide bundle 与 release 元数据中的integrity字段一致pyodide_extra.capnp中integrity字段的注释也印证了这一点只有本地构建的 “dev” bundle 跳过校验其他 bundle 若缺失预期校验和本身即为错误。这与第二节“将来支持多版本 Pyodide、动态下载”的规划直接衔接——动态下载的前提首先是可校验。四、从源码结构看运行时加载链路把上述组件串起来可以推断出当前 Python Worker 的加载链路以“从源码结构看”表述逐环节有文件可依入口Python 模块不能直接作为 ES6 入口因此 python-entrypoint.js 作为 ES6 入口被当作用户 bundle 的一部分嵌入。它只做两件事从pyodide:python-entrypoint-helper一个 BUILTIN 模块见 python-entrypoint-helper.ts引入initPython、createImportProxy等并在设置好“动态 import JS 模块”的代理后才调用initPython()。文件头注释解释了为何要这一层间接BUILTIN 模块不能导入 INTERNAL 模块、也不能直接看到用户模块入口文件恰好处于唯一能同时看到两者的位置。桥接internal/python.ts 负责 Emscripten 初始化与 Pyodide 引导从PyodideMetadataReader读取 worker 模块、从EmbeddedPackagesReader获取 stdlib 文件布局并构建只读文件系统由 internal/tarfs.ts 提供再执行用户模块。快照internal/snapshot.ts 完成内存快照的收集与恢复PyodideMetadataReader携带memorySnapshotArtifactBundler携带 validator 阶段产出的快照二者共同实现“验证期生成、运行期恢复”的冷启动加速。约束internal/pool/emscriptenSetup.ts 运行在“vanilla V8 isolate”中不能导入 C 扩展模块见 AGENTS.md 的醒目提示这是 Emscripten 池化与 workerd 自身 isolate 隔离边界之间的实现约束。测试方面AGENTS.md 说明 Python Worker 的测试位于src/workerd/server/tests/python/由py_wd_test.bzl宏展开它处理%PYTHON_FEATURE_FLAGS模板替换、多 Pyodide 版本变体、快照的生成/加载以及每个版本的 compat flag 隔离测试默认sizeenormous每个测试会按支持的每个 Pyodide 版本生成一个变体。五、动手运行 samples/pyodide 示例README 指引“Seesamples/pyodide/for an example using this in its current state.”示例只有两个文件非常小适合本地快速验证整条链路。samples/pyodide/config.capnp 声明了一个监听*:8080的 HTTP socket绑定到名为main的 serviceworker 配置如上节所示pythonModule embed ./worker.py表明 workerd 把 Python 源文件作为模块嵌入compatibilityFlags打开python_workers与python_workers_20250116。samples/pyodide/worker.py 是最小的 Python Workerfrom js import Response from workers import WorkerEntrypoint class Default(WorkerEntrypoint): def fetch(self, request): return Response.new(hello world) def test(): print(Hi there, this is a test)可以看到两个关键 APIfrom js import Response从 JS 侧导入 Web API与from workers import WorkerEntrypointPython SDK 的入口基类fetch是请求处理入口。workers这个 Python SDK 包对应 src/pyodide/internal/workers-api/ 下冻结的 SDK 源码src/workers/__init__.py、_workers.py等AGENTS.md同时说明该 SDK 现已迁至独立的 workers-py 项目并从 PyPI 安装仓库中保留的是向后兼容版本。运行方式需要本地已构建出 workerd 可执行文件例如通过 Bazel 构建//src/workerd/workerd:workerd目标后workerd serve samples/pyodide/config.capnp # 然后 curl http://localhost:8080 # 预期返回hello world注意示例配置没有显式写--experimental因为当前 Python Workers 的开关已由python_workers*系列 compat flag 表达README 中“需要experimental兼容性开关”的表述反映的是早期阶段的状态阅读时应以仓库中当前配置为准。六、下一步自定义链接 Emscripten 二进制README 最后一段给出了明确的性能优化方向同样值得完整保留为了降低内存占用和启动时间我们也希望链接我们自己版本的 Emscripten 二进制pyodide.asm.js和pyodide.asm.wasm。由于 Emscripten 动态链接的限制Pyodide 官方产物被静态链接进去的、很少用到的“垃圾”撑大了体积。希望下一个 Pyodide 版本的发布产物中包含所有编进 Pyodide 的静态库。那样我们就能在构建流程里做一个“修改版的最终链接步骤”丢掉我们不需要的内容。这段规划的工程含义是当前 workerd 消费的是 Pyodide 的成品动态链接 wasm无法裁剪一旦上游把静态库暴露为发布产物workerd 就能在 helpers.bzl 的构建规则里介入最终链接按 Python Worker 实际用到的符号集做静态裁剪。这与第二节“多版本 动态获取”的路径互为表里一个解决“体积/启动”一个解决“版本/依赖”最终让编译进二进制的只剩真正需要的部分。七、小结回到 src/pyodide/README.md 的全局信息它做了什么把 Pyodide 的 emscripten 二进制 stdlib 打成一个 capnp bundle 编入 workerd用自研精简加载器internal/python.ts一族模块替代官方pyodide.js砍掉包加载器并新增内存快照它为什么这么做升级 Pyodide 大版本有破坏性风险必须支持多版本 pin 与动态获取而静态编入是“最快跑通”的过渡方案它现在长什么样python-lock/双 lockfile、pyodide_extra.capnp的 release 元数据、pyodide.h的 bundle 管理/完整性校验/快照接口以及 samples/pyodide/ 可运行的最小示例它要去哪里动态下载多版本 Pyodide bundle、配置期包管理、自定义最终链接以裁剪 emscripten 产物。想继续深入时建议按顺序阅读src/pyodide/BUILD.bazel 与 src/pyodide/helpers.bzl构建与 bundle 装配、src/pyodide/pyodide_extra.capnprelease 元数据 schema、src/workerd/api/pyodide/pyodide.hC 运行时接口、src/pyodide/internal/python.ts运行时桥接实现以及src/workerd/server/tests/python/下的测试。【免费下载链接】workerdThe JavaScript / Wasm runtime that powers Cloudflare Workers项目地址: https://gitcode.com/GitHub_Trending/wo/workerd创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/16 19:32:33

美容院微信小程序模板源码深度定制指南

简介:这是一套专为美容院行业定制的微信小程序模板源码,面向中小型美容机构管理者及前端开发者,解决线上预约、服务展示与客户管理等核心运营需求。资源包共135个文件,涵盖32个JS逻辑文件(如order.js、makeOrder.js、c…

2026/9/16 19:32:33

HashMap线程安全问题与ConcurrentHashMap解决方案

1. HashMap在多线程环境下的致命陷阱第一次遇到HashMap在多线程环境下崩溃的场景,至今记忆犹新。那是一个电商促销日的凌晨,系统突然开始出现诡异的现象:CPU占用率飙升到100%,订单数据莫名其妙丢失,而最可怕的是——这…

2026/9/16 19:32:33

Linux日志排查与安全审计实战:从碎片到时间线

1. 这不是日志清单,而是一份Linux系统“数字尸检报告”操作手册你有没有遇到过这样的场景:凌晨三点,监控告警疯狂闪烁,服务突然502,但top里CPU和内存都风平浪静;或者安全团队甩来一份渗透测试报告&#xff…

2026/9/16 20:37:41

分子动力学模拟小麦润湿过程的参数配置与优化

1. 项目概述"基于分子动力学的小麦润湿微观研究详细复现方案"是一个典型的计算材料科学项目,旨在通过分子动力学模拟技术揭示水分与小麦微观结构相互作用的机制。这类研究对于理解粮食储存、食品加工中的水分迁移行为具有重要价值。作为一名长期从事计算化…

2026/9/16 20:37:41

FPGA静态代码检查工具VHawk-Lint:规则覆盖与性能实测

FPGA开发圈子里有个老生常谈的痛点:代码能综合、仿真能过,一上板就“翻车”。有人在时序收敛上死磕三天,最后发现根因是跨时钟域没做同步;有人调了半天逻辑,结果是case语句漏了default,综合器默默推断出锁存…

2026/9/16 20:32:41

C#跨域访问共享文件夹:WNetUseConnection账号认证与实战

搞企业内网开发的朋友应该都遇到过这个需求:上位机要读取文件服务器上的共享文件夹,系统需要把采集数据写到另一台机器的共享目录,运维脚本要跨机器拉取报表。在同一个域里倒还好说,程序跑起来用当前 Windows 身份就能访问。但一旦…

2026/9/16 12:52:37

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/16 0:04:09

PHP源码部署实战:从环境配置到运行情侣游戏全攻略

简介:这是一套面向情侣互动场景的PHP完整源码,集成情侣飞行棋、真心话大冒险、情趣骰子等玩法,并内置完整分销制度,可自定义多种返佣比例,源码完全开源无加密,支持微信无感自动授权登录与第三方授权&#x…

2026/9/15 14:22:53

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/15 21:31:11

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/15 11:42:23

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码