Bun 1.4 的 bun test --parallel 将 4 秒的测试套件缩短到约 1 秒
我有一个由 20 个测试文件组成的测试套件运行一次需要 4 秒多。我只加了一个参数--parallel耗时就降到了 1 秒。接着我尝试进一步压榨性能并找到了这个参数停止生效的临界点——事实证明这取决于测试实际执行的工作类型而不是文件的数量。Bun 1.4 于 2026 年 8 月 20 日发布带来了bun test --parallel它会将测试文件分发到多个 worker 进程中并行执行而不是在单个进程里逐个运行。我在一台 4 核 Intel Xeon 虚拟机上KVM4 个逻辑 CPU无 cgroup 限制运行 Bun 1.4.2我想弄清楚这个参数到底能带来多少收益、它的上限在哪里以及文档中隐含--isolate这句话在实际中意味着什么。我写了 20 个测试文件每个文件两个测试其中每个测试都会先await一个 100ms 的setTimeout再执行断言——用来模拟拖慢大量真实集成测试的 API 调用和防抖逻辑。每组运行三次最快与最慢之间的差距在 15ms 以内模式墙钟耗时bun test串行4.04s--parallel14.06s--parallel22.05s--parallel4默认值 CPU 核心数1.03s--parallel80.63s不带参数时--parallel默认使用 CPU 核心数在这台机器上是 4。仅此一项就把套件从 4.04s 降到了 1.03s提速 3.9 倍这与 4 个 worker 分摊 20 个文件的情况几乎完全吻合。让我惊讶的是在这台只有 4 个逻辑核心的机器上--parallel8仍然在继续提升降到了 0.63s。我稍后会解释原因因为这是本文最重要的一部分。另一面的读数CPU 密集型测试会在核心数处撞墙一个await setTimeout的测试在等待时其实并不占用 CPU它只是占着一个坑位。于是我构建了第二个套件结构相同20 个文件、每个文件 2 个测试但这次每个测试运行真实计算一个筛选到 2000 万的质数筛prime sieve它占用真正的 CPU 时间没有任何等待。模式墙钟耗时bun test串行6.1s--parallel16.2s--parallel23.3s--parallel41.8s--parallel61.9s--parallel81.8s这个数字才是反对头条结论的证据。扩展到 4 个 worker 时缩放几乎呈线性与 4 个物理核心匹配然后就不再提升了。增加到 6 个或 8 个 worker 没有任何收益在某些轮次中甚至比 4 个稍慢——大概是进程争夺相同核心时产生了上下文切换开销。--parallel调度的是操作系统进程它并不能凭空变出更多 CPU。对于真正受 CPU 限制的套件关键数字不是你有多少个文件而是nproc。把两张表放在一起真正的规律比任何一张单独的表都更简单对于大部分时间在等待的测试--parallel可以扩展到超过你的核心数而对于大部分时间在计算的测试它做不到。大多数真实套件是两者的混合所以诚实的建议是对自己的套件做基准测试而不是假设它符合某一条曲线。隐含--isolate到底隔离了什么文档说--parallel隐含--isolate并将其描述为即使两个文件落在同一个 worker 上每个文件也会获得全新的全局对象。我想确切知道它重置了什么因为这种措辞没有说清是按文件隔离还是更粗或更细的粒度。我写了一个带有顶层计数器的模块和四个导入它并打印所见值的测试文件// shared.ts let count 0; export function bump() { count; return count; }在普通bun test下整个运行共享一个进程和一个模块缓存因此计数器会按文件实际运行的顺序跨文件递增file-4 sees counter 1 file-1 sees counter 2 file-2 sees counter 3 file-3 sees counter 4在--parallel下每个文件看到的都是1file-1 sees counter 1 worker 1 file-2 sees counter 1 worker 1 file-3 sees counter 1 worker 1 file-4 sees counter 1 worker 1四个文件都在同一个 worker 进程中运行相同 PID所以这与操作系统进程隔离无关——而是在单个进程内每个文件拥有全新的 JS 全局对象与文档描述完全一致。在--parallel上加上--no-isolate泄漏立刻回来了又变成了1, 2, 3, 4与串行相同。那一行文档摘要没有说清楚的部分是隔离是按文件而不是按测试。同一个文件内的三个测试在--parallel下运行时计数器会依次看到1, 2, 3之间没有重置。如果你的测试依赖模块级设置在每一个测试而不仅是每个文件都重新初始化那么--isolate无法提供这一点无论是否并行。Bun 还会把BUN_TEST_WORKER_ID和JEST_WORKER_ID设置为 worker 的从 1 开始的索引我在上面的测试中打印两者确认过——如果你在移植一个以该变量作为数据库名或端口键的 Jest 配置这一点值得了解。--bail停止的是尚未启动的文件而不是正在运行的文件文档描述得很精确协调器按文件粒度处理--bail一旦达到失败阈值它就不再启动新文件但已在运行的文件会继续跑完。我针对 20 个文件测试了这一点其中第一个文件有一个耗时 300ms 的失败测试。不加--bail在--parallel下无论是否失败20 个文件全部运行19 pass 1 fail Ran 20 tests across 20 files. [1.53s]加上--bail后Bailed out after 1 failure 3 pass 1 fail Ran 4 tests across 4 files. [320.00ms]运行了 4 个文件而不是 1 个。这与失败发生时已有 4 个 worker 正在执行相匹配其余 16 个文件从未启动。这在 CI 中能节省大量时间这里从 1.53s 降到 0.32s但这也意味着在--parallel下使用--bail你无法得知那 16 个未触碰的文件中是否还有其他失败——包括那些与导致首次失败的问题毫无关系的失败。覆盖率合并正确、非法输入被干净拒绝、单个坏文件不会拖垮整个运行我还检查了另外三件事简要说明覆盖率合并我把一个模块的三个函数拆分到三个测试文件中每个文件覆盖一个函数并比较了--coverage输出。串行与--parallel --coverage报告的数值完全相同——函数覆盖率 75%、行覆盖率 60%、未覆盖行范围一致——因此文档所称的跨 worker 覆盖率合并完全成立。非法输入在任何测试运行前就被拒绝--parallel0、--parallel-1和--parallelabc都产生了同样简洁的错误信息和退出码 1且没有执行任何内容error: --parallel expects a positive integer, received 0一个文件的崩溃不会拖垮整个运行我有一个测试文件在模块加载时抛错与文件内任何测试无关。在--parallel下该批次中的另外三个文件仍然运行并通过崩溃被报告为独立的 error而不是与断言失败混在一起bun test v1.4.2 (744846f84) 4x PARALLEL tests-crash/cr2.test.ts: # Unhandled error between tests ------------------------------- error: boom at module load time ------------------------------- 3 pass 1 fail 1 error Ran 4 tests across 4 files. [11.00ms]横幅中那行4x PARALLEL也是从 CI 日志确认实际运行了多少 worker 的最简单方式无需向自己的测试代码添加任何内容。我在这条路上犯过的错我第一次构建CPU 密集型套件时用while (Date.now() - start 100) {}来模拟真实工作期望它的表现和质数筛套件一样。结果并非如此在一台 4 核机器上--parallel8一直持续变快远超真实 CPU 工作应该达到的平台期形状与 IO 密集型套件相同。我花了一段时间假设 Bun 在调度上做了什么聪明的事才想明白真正的原因一个检查墙钟时间的自旋循环只需在截止时间之后被调度一次就会注意到时间已过并退出。它表现得像 sleep 而不是计算因为操作系统想抢占它多久就多久循环根本不在意——只要它下次被调度检查时真实时间已经流逝即可。这就是我重建 CPU 密集型套件时改用真正的质数筛、完全不检查时钟的原因也就是上面表格中的版本。自己动手跑一遍这是生成第一张表的精简版脚本。需要 Bun 1.4 或更高版本。curl -fsSL https://bun.sh/install | bash mkdir bun-parallel-demo cd bun-parallel-demo for i in $(seq -w 1 20); do cat t$i.test.ts EOF import { test, expect } from bun:test; test(io-$i, async () { await new Promise((r) setTimeout(r, 100)); expect(1 1).toBe(2); }); EOF done bun test # 串行基线 bun test --parallel # 默认使用你的 CPU 核心数 bun test --parallel8 # 超出核心数继续压榨因为这些测试只是在等待把生成的测试主体替换为真实计算一个质数筛、一次排序任何不带定时器的东西就能看到平台期而非持续扩展并与你自己机器上的nproc对比。该怎么用在为现有套件开启--parallel之前先弄清楚你的套件到底属于哪种类型。如果你的大部分测试都在等待定时器、socket 或数据库往返把--parallel提高到超过核心数就是免费的速度提升值得立刻尝试。如果你的测试在进程内做真实计算那么超过nproc就没有任何收益应该把--parallel设为该数值而不是猜一个更大的数。无论哪种情况在依赖--isolate保证正确性之前先检查你的测试在模块作用域到底共享了什么它重置的是文件之间的状态而不是同一文件内测试之间的状态而这个缺口正是测试套件变得不稳定的常见温床。相关阅读延伸外链以下为推荐的相关技术教程来自致知笔记如何将笔记本电脑连接到外接显示器如何检查 IP 地址是静态还是动态Static/Dynamic IP如何在 Windows 11/10 中创建密

相关新闻

page_alloc page_expected_state

page_alloc page_expected_state

检查页的当前状态是否符合“预期状态”。它是页面释放/分配路径上调试检查的一部分,用于发现页状态异常(“坏页”)。一、函数签名static inline bool page_expected_state(struct page *page,unsigned long check_flags)参数参数类型含义page…

2026/10/10 8:42:02 阅读更多 →
Python aigc-zoo 包实战案例与常见错误

Python aigc-zoo 包实战案例与常见错误

1. 引言aigc-zoo 是一个面向 AIGC(人工智能生成内容)场景的 Python 工具包,旨在把文本生成、图像生成、音频合成、视频生成等常见能力封装成统一、易用的接口。它适合希望在项目中快速接入生成式 AI 能力、又不想被各家厂商 SDK 差异困扰的开…

2026/10/12 10:38:37 阅读更多 →
【FHE 同态加密】我们如何实现同态加密推理(六):Key-Switch 重线性化——一个数量级(2^73 噪声)决定整个设计

【FHE 同态加密】我们如何实现同态加密推理(六):Key-Switch 重线性化——一个数量级(2^73 噪声)决定整个设计

【FHE 同态加密】我们如何实现同态加密推理(六):Key-Switch 重线性化——一个数量级(2^73 噪声)决定整个设计 关键词:同态加密 | FHE | CKKS | Key-Switch | …

2026/10/9 14:54:43 阅读更多 →

最新新闻

冈某云音乐榜单爬虫实战:从抓包分析到批量保存(含代码对照)

冈某云音乐榜单爬虫实战:从抓包分析到批量保存(含代码对照)

前言很多音乐爱好者都有收藏歌单的习惯,但手动一首首下载不仅繁琐,而且效率极低。本文将详细介绍如何利用 Python 编写一个冈某云音乐榜单爬虫。我们将跳过复杂的逆向工程,利用外链播放器接口的特性,实现从榜单解析到歌曲 ID 提取…

2026/10/13 10:22:52 阅读更多 →
【STM32C5教程】(3)GPIO 按键输入实验

【STM32C5教程】(3)GPIO 按键输入实验

欢迎关注 youcansxidian【嵌入式软件AI编程】专栏 【STM32C5教程】(1)STM32C5系列介绍 【STM32C5教程】(2)STM32CubeMX2 安装与STM32C5闪灯 【STM32C5教程】(3)GPIO 按键输入实验 1. 项目简介 1.1 实验目标…

2026/10/13 10:22:52 阅读更多 →
RK3588与Jetson双芯协同:边缘AI智能盒子硬件架构与推理性能实测

RK3588与Jetson双芯协同:边缘AI智能盒子硬件架构与推理性能实测

1. 从一块开发板到一台“智能盒子”:我为什么盯上了这个组合前阵子有个做边缘计算的朋友甩给我一个链接,说“你看看这个,RK3588加Jetson的AI盒子,有点意思”。我当时第一反应是:这俩放一起?RK3588是瑞芯微的…

2026/10/13 10:22:52 阅读更多 →
从‘补全‘到‘任务托管‘:编码Agent进入云端化+多子代理阶段,开发者要不要把整个任务交出去?

从‘补全‘到‘任务托管‘:编码Agent进入云端化+多子代理阶段,开发者要不要把整个任务交出去?

从“补全”到“任务托管”:编码 Agent 进入云端化 多子代理阶段,开发者要不要把整个任务交出去? 一、正在发生的变化:Agent 不再只是“更聪明的补全” 如果你还在把编码 Agent 理解成“自动补全的高级版”,那么这个…

2026/10/13 10:22:52 阅读更多 →
Android RTSP播放Demo完整拆解:选型、参数配置与高频避坑指南

Android RTSP播放Demo完整拆解:选型、参数配置与高频避坑指南

简介:一份可直接运行的 Android RTSP 播放示例工程,面向需要在直播、网络摄像头或视频监控等场景中接入实时流媒体的 Android 开发者,既适合入门学习也适合快速原型验证;其核心通过 MediaPlayer 加载 rtsp:// 地址,完整…

2026/10/13 10:22:52 阅读更多 →
元宝    LeetCode 332. Reconstruct Itinerary Java Implement

元宝 LeetCode 332. Reconstruct Itinerary Java Implement

Core idea: Hierholzer’s algorithm for an Eulerian path. A naive lexical greedy walk can get stuck (e.g. “JFK→KUL” dead-ends when “JFK→NRT→JFK→KUL” is the answer). The fix: keep walking greedily, but only append each airport on the way back up — d…

2026/10/13 10:21:51 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/12 18:11:17 阅读更多 →