BAML 接口多态分派基准测试:polymorphic-dispatch-100k workload 深度解析
编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载本文围绕 BAML 仓库内置基准套件tools/speedtest中的interfaces::polymorphic dispatch 100kworkload 展开完整解读其 BAML/Python/TypeScript 三语言对照实现、接口多态调度的底层原理并给出该 workload 在本地基准工具链中的运行、验证与剖析方法。读完本文你将掌握如何读懂并运行这类接口分派型性能用例并能结合源码理解 BAML 运行时开放式世界方法分派的设计取舍。一、workload 在基准套件中的定位在 baml_language/tools/speedtest/workloads 目录下基准用例按主题分目录组织compute/纯计算、classes/类与方法调用、interfaces/接口相关、concurrency/并发、string/字符串。本篇文章所讨论的 polymorphic-dispatch-100k.md 属于interfaces/类别聚焦一个核心问题当程序通过接口类型existential 接收者调用方法时运行时如何把调用分派到具体实现类的方法上以及这种分派在 10 万次循环中的成本是多少。同目录下的三个兄弟 workload 从不同角度度量接口机制match-dispatch-100k.md通过match模式匹配实现手动分派let d: Dog ...field-access-100k.md度量接口字段读取该文档明确指出接口方法分派本来就是开放式世界的而字段读取路径曾由编译期 implementor 开关改为virtual_load_field因此字段访问才是成本迁移最明显的路径本文主角 polymorphic-dispatch-100k.md度量接口方法的多态分派接收者每次交替为两种不同实现类。二、BAML workload 全文与逐段解读原文档的 BAML 部分定义了一个完整的形状面积程序使用interface、implements、for循环与多次方法分派interface Shape { function area(self) - int } class Square { side: int implements Shape { function area(self) - int { return self.side * self.side } } } class Rect { w: int h: int implements Shape { function area(self) - int { return self.w * self.h } } } function pick(i: int) - Shape { if i % 2 0 { return Square { side: i }; }; return Rect { w: i, h: 3 }; } function area_of(s: Shape) - int { return s.area() } function main() - int { let acc 0; for (let i 0; i 100000; i 1) { acc area_of(pick(i)); }; return acc; }逐段理解接口声明interface Shape { function area(self) - int }声明一个仅含area方法的接口self为隐式接收者。注意这里area是必需方法没有默认实现体。实现类Square字段side与Rect字段w、h通过implements Shape { ... }块分别提供area的实现。两个类的area读取不同的字段、使用不同的公式因此分派必须依据接收者的实际实现类而不是共享布局。多态构造pick(i: int) - Shape根据i的奇偶交替返回Square或Rect——两者都装箱为接口类型Shape。这正是多态的来源pick的返回类型是抽象接口具体实现类在运行时才确定。透过接口调用area_of(s: Shape) - int { return s.area() }在一个静态类型为Shape的参数上直接调用方法运行时必须解析s的真实实现类并定位其area方法体。主循环main以 10 万次迭代累加area_of(pick(i))的结果。每次迭代包含一次多态构造 一次接口方法分派 一次整数乘法/加法构成稳定的分派压力。在 10 万次迭代中area的实际调用会以约 1:1 的比例交替落在Square与Rect上且两种实现的字段布局不同side与w/h不在同一槽位因此每次调用都必须真正依赖接收者的实现信息完成分派不存在共享布局下的侥幸优化空间。三、跨语言对照Python 与 TypeScript 的等价实现原文档为同一 workload 提供了 Python 与 TypeScript 版本二者与本仓库基准工具的设计直接相关——runner.py会用它们做跨语言输出一致性校验见下文第四节。Python 对照实现class Square: __slots__ (side,) def __init__(self, side): self.side side def area(self): return self.side * self.side class Rect: __slots__ (w, h) def __init__(self, w, h): self.w w; self.h h def area(self): return self.w * self.h def pick(i): return Square(i) if i % 2 0 else Rect(i, 3) acc 0 for i in range(100000): acc pick(i).area() print(acc)要点__slots__显式限定字段以贴近紧凑布局pick用三元表达式交替构造主循环等价于 BAML 版本最终print(acc)输出结果。TypeScript 对照实现class Square{constructor(side){this.sideside}area(){return this.side*this.side}} class Rect{constructor(w,h){this.ww;this.hh}area(){return this.w*this.h}} function pick(i){return i%20?new Square(i):new Rect(i,3)} let acc0;for(let i0;i100000;i){accpick(i).area()}console.log(acc)三份代码保持相同的语义与循环结构输出一致都是同一整数累加结果这是基准可比性与正确性的基础。四、workload 的加载机制Markdown 即基准定义tools/speedtest采用Markdown 即 workload 定义的设计。加载器 loader.py 解析每个.md文件第一行#标题作为 workload 全名例如interfaces::polymorphic dispatch 100k其父目录名作为 categoryinterfaces正则提取## BAML、## Python、## Typescript三个代码块parse_workload_md三个代码块任一缺失则整个 workload 被跳过if not baml or not python or not js: return None目录以排序后的rglob(*.md)扫描形成有序 workload 列表。loader.py还预留了## eval-setup小节可选用于执行一段 Python 设置代码并通过$$var模板_DDTemplate单$为字面量对三份源码做变量替换——本 workload 未使用该机制但它是同套件中复用型 workload 的扩展点。此外export_baml.py 将全部 workload 的展开后BAML 源码以 JSON 数组{name, category, baml}输出到 stdout其文件头注释明确说明这是让 Rust 基准套件crates/baml_tests复用这些 workload 作为 CodSpeed 基准的桥接层避免重复实现.md解析与模板逻辑。也就是说这份polymorphic-dispatch-100k.md不仅服务于 Python 侧计时还被导出供 Rust 侧持续基准复用。五、如何运行与验证该 workload基准入口是 cli.py 定义的speedtest命令子命令run/compare/open/list/baselines未给子命令时默认视为run。只运行本文 workload 的典型方式speedtest run --filter polymorphic --build核心命令行参数依据 cli.py参数作用默认值--build先cargo build --release -p baml_pack_host -p baml_cli再基准关闭--filter只跑名称包含该子串的 workload可重复大小写不敏感空跑全部--only-baml跳过 python/node/bun 计时关闭--runs N固定每 workload 跑 N 次覆盖自适应计时None自适应--measurement-time SECS自适应计时下每 workload 的目标测量秒数5.0--baml PATH指定 baml-cli 路径默认target/release/baml-cli自动推导--tag NAME为本轮结果打标签类似 git tag无--profile用samply record --save-only采集 CPU profile要求 PATH 中有 samply关闭--profile-baml PATH指定 profiling 构建的 baml-cli由 release 路径推导--results-dir结果保存目录~/.speedtest/runner.py中与本文 workload 直接相关的执行流水线为打包pack_baml调用baml-cli pack main --file workload.baml -o out把 BAML workload 打成独立可执行二进制polymorphic_dispatch_100k.packed期望值运行打包后的二进制取最后一行 stdout 作为期望输出跨语言校验若环境中存在python3/node/bun分别运行python3 -S py_file、node js_file、bun js_file任一输出与 BAML 期望值不一致则在该行标记MISMATCH结果表中显示(!)。这是保证三语言 workload 语义等价的硬性关卡计时默认走time_command_adaptive——先丢弃 3 次预热用预热中位数估算单次耗时再按measurement_time反推采样数并夹在[min_samples5, max_samples100]之间--runs指定时走time_command_fixed固定次数。统计输出中位数、标准差、样本数与 min/max结果落盘保存本轮数据到results_dir并写入baselines/branch/latest可--tag打标随后可用speedtest compare branch-a branch-b对比基线、speedtest open打开浏览器 UI。若--profile开启还会以samply record --save-only -o slug.json profiling-baml-cli run --file baml_file -f main -- main的形式采集 profile 文件并随结果保存可用于定位分派热点。六、接口分派的底层实现视角从仓库源码可以进一步印证该 workload 所压测的运行时机制。1. 开放式世界的 impl 表烘焙。bex_vm的 interface_registry.rs白盒测试断言打包进Program::packages的 impl 规则其方法表是PROVIDED-ONLY——只包含 impl 块显式声明的方法绝不烘焙一份接口默认方法的拷贝默认方法由分派时通过接口对象的default_fn现场采用。对本文 workload 而言Square implements Shape与Rect implements Shape各自的方法表恰好只含area分派只需在接收者的实现规则中查到area - area的方法体 FQN 即可。2. 分派必须依赖接收者。field-access-100k.md的注释提供了关键背景接口方法分派本就是开放式世界的而接口字段读取曾依赖编译期 implementor 开关后来改为virtual_load_field。从源码结构看polymorphic-dispatch-100k正是用来持续盯住方法分派这条路径的成本——两个实现类的area读取不同槽位的字段说明每次调用都必须走接收者相关的解析无法退化为共享布局直读。3. 与 match 手动分派的对照。同目录 match-dispatch-100k.md 使用match (a) { let d: Dog d.noise() ... }显式按类型分支等价于 Python 的isinstance链与 TypeScript 的instanceof链。将两个 workload 的耗时并排对比即可看出运行时多态分派与源码级手动分派在 BAML 运行时中的相对成本这正是speedtest compare用武之地。七、扩展与延伸阅读阅读同目录 field-access-100k.md了解接口字段读取virtual_load_field这一成本迁移路径的专项度量阅读 match-dispatch-100k.md对比 match 手动分派想要把本 workload 加入 Rust 侧 CodSpeed 基准可复用 export_baml.py 的 JSON 导出想要复现完整基准流程从 runner.py 与 cli.py 入手配合--build构建baml-cli与baml_pack_host即可在本地跑通打包、校验、计时、对比的完整闭环。适用前提说明以上运行方式与参数以当前仓库baml_language/tools/speedtest的实际实现为准本地运行需要 Rust 工具链构建baml-cli/baml_pack_host、可选的python3/node/bun用于跨语言校验以及可选的samply用于--profile。本文不包含任何具体性能数字基准结果应在本机环境实测获得。赞分享编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载相关推荐BAML 接口 Match 分发基准深度解析interfaces::match dispatch 100k 实测用例全解读BAML 接口 Match 分发基准深度解析interfaces::match dispatch 100k 实测用例全解读 BAMLthe programm编程语言AI Agent编译器CLI人工智能awesome-computer-vision 资源获取完整指南一份清单搞定论文、数据集与工具库awesome computer vision 资源获取完整指南一份清单搞定论文、数据集与工具库 刚进入计算机视觉CV方向时你大概率遇到过这种状况论文编程语言AI Agent编译器CLI人工智能微信批量发送终极指南3分钟搞定1000条消息的免费神器微信批量发送终极指南3分钟搞定1000条消息的免费神器 你是否曾为给微信好友逐一发送相同消息而烦恼无论是节日祝福、活动通知还是产品推广手动发送不仅耗时耗力编程语言AI Agent编译器CLI人工智能上一篇PaddleSpeech Conformer 训练性能基准测试实践AISHELL-1 Benchmark 脚本、运行流程与日志解析下一篇5分钟上手浏览器远程桌面mstsc.js终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考