平台

navigator.hardwareConcurrency 与 Web Worker 规划

理解 navigator.hardwareConcurrency,选择 Web Worker 池大小,并在不把浏览器提示当作核心数的前提下测试并发。

文档中心

想直接进入 平台 文档吗?

这篇文章属于博客内容库。若你要步骤化配置、参考说明和持续更新,请直接进入对应 docs 分区。

navigator.hardwareConcurrency 是浏览器提供的并发提示,不保证页面可以同时运行同样多的任务。应把它作为有界 Worker 池策略的一个输入,再测量队列等待、完成时间、内存压力和响应性。有效的规划会在新增 Worker 只增加争用之前停止扩容。

硬件并发提示进入有界 Worker 池的示意图

这个值表示页面可见的逻辑处理器数量,浏览器也可能为了限制并发而报告更小的值。设备和视口指南说明了另一个边界:浏览器暴露的值是兼容性输入,不是完整的设备描述。

这个值表示什么

MDN 的 Navigator.hardwareConcurrency 参考将它定义为用户计算机上可运行线程的逻辑处理器数量。文档也说明浏览器可能报告少于机器实际拥有的处理器。因此它适合作为初始估计,却不能证明物理核心数、当前 CPU 负载或页面可用内存。

窗口中的 navigator 和 Worker 的全局作用域都可以读取这个属性。它不会创建线程、预留 CPU 时间,也不会让任务自动并行。Worker 仍通过消息通信,页面仍要承担序列化、调度、分配和同步成本。

把变化视为正常的兼容性事件。不同浏览器版本、操作系统策略、电源模式、隐私设置或执行上下文可能暴露不同提示值。不要把它当作身份信号、授权依据,或收集更详细硬件资料的理由。

将提示转成 Worker 策略

从小型池和队列开始。对于彼此独立的 CPU 密集型任务,初始上限不应高于提示值,通常还应更低。要为页面、输入处理、网络、渲染和操作系统保留容量。I/O 密集型任务大量等待时,所需 Worker 可能更少。

WHATWG Worker 模型把 Worker 定义为独立执行上下文,通过消息与创建者通信。因此队列很重要:只发送有界批次,适当传输大型缓冲区,并定义取消任务或 Worker 失败时的行为。池应能停止接收任务,而不是无限增长。

可以使用 min(availableHint, configuredMaximum) 这样的策略,而不是直接把提示值复制成池大小。为移动或内存受限上下文设置独立上限;如果已知任务成本很高,则让应用自身的上限优先。配置上限是产品决策,浏览器提示只是输入。

测量饱和点和响应性

测试真实任务,而不是空循环。记录队列等待、执行时间、端到端完成时间、失败或取消的任务、内存使用,以及主线程响应性。在代表性数据上比较单个 Worker、小型池和更大的池。当吞吐趋于平坦,或延迟、内存、交互质量变差时,应停止增加并发。

分别运行冷启动和热运行。短任务可能主要受 Worker 启动和脚本加载影响,长任务则可能受计算或消息传输限制。记录浏览器版本、输入规模、设备类别和电源状态,方便比较后续结果。不要仅凭时间推断机器的物理拓扑。

把失败路径纳入规划。Worker 被终止、消息被拒绝、内存不足或页面可见性改变时,应将任务放回有界队列或进入清晰的错误状态。取消必须释放缓冲区并从统计中移除任务。重试要有上限,避免失败任务长期占满池。

保持隐私和兼容性边界

这个提示本来就比较粗略,也可能被降低。缺少该属性、值很小或与先前观察不一致时,页面仍应工作。检测 Worker 支持情况,并为短任务提供主线程或顺序执行的回退。不要把 hardwareConcurrency 与计时、图形、字体或存储观察结果组合来识别个人或设备。

当资源选择影响电池、流量或上传时,用用户能理解的方式说明原因。本地 Worker 池不会授权把数据发送到别处。如果流程从本地处理改为远程服务,应取得明确选择并说明哪些数据离开设备。日志只保留运行队列所需的测量,不记录原始内容或不必要的硬件细节。

先分类任务再选择池

先区分 CPU 密集、网络等待和共享状态任务。CPU 密集型独立任务可以逐步增加 Worker,直到吞吐不再上升。网络任务通常受服务端响应限制,增加 Worker 只会增加请求压力。

把独立任务与有序阶段分开。独立项目可以乱序完成,再用序号恢复展示顺序。有依赖的阶段应显式保留依赖,不要为每一步都启动 Worker。

测量单位要固定,包括输入准备、消息传输、Worker 执行、结果处理和清理。否则只测 Worker 阶段会掩盖主线程上的准备成本。

先写出单项任务的取消和失败行为,再决定池大小。没有明确终止条件的任务会占住 Worker,令任何并发比较失去意义。

设计队列生命周期

有界队列需要准入、执行和完成规则。达到上限时可以拒绝新任务、替换过期刷新,或显示等待进度,但不要静默累积无限输入。

让一个组件拥有队列状态,Worker 只管理当前任务。消息携带短任务标识,结果携带成功、失败或取消状态,迟到的结果也不会覆盖新任务。

对运行中的任务设置超时和取消路径。完成时只结算一次,释放 Worker 并更新下一次决策需要的测量。

计算传输与内存成本

结构化克隆可能复制对象,可转移的缓冲区则能在支持时转移所有权。用真实输入比较两种方式,不能只看计算时间。

限制输入大小并在完成后释放引用。页面、队列和 Worker 同时保留大型数组,会让少量活动任务也产生很高的峰值内存。

结果也要有保留策略。只渲染当前视图需要的结果,对大列表分页,避免为日志和显示保存重复副本。

适配可见性与电量

页面隐藏时可以暂停非必要任务或降低优先级。恢复可见后重新检查队列,因为搜索结果或预览可能已经被替换。

移动设备上的持续并发会消耗电量并产生热量。可提供偏向响应性和续航的模式,该模式调整应用上限,不把提示值解释成电池容量。

状态变化只用于调度,不用于识别用户或设备。除非用户明确选择,不要把可见性或电源观察发送到服务端。

让回退路径可观察

在使用点检测 Worker 构造器和消息能力,不可用时采用顺序路径。回退应保持相同的结果格式,并尽量保留取消操作。

向用户显示准备、处理中、暂停和失败等状态,但不要把 Worker 数量说成速度保证。

测试 Worker 崩溃、结果格式错误、超时、传输期间取消和页面导航。每个分支都要结算任务、释放资源,并让其他任务继续使用队列。

重试只在可能改变结果时提供,并设置次数上限。永久失败应有清楚的说明,而不是让界面无限等待。

将测量转成可回退的决策

用代表性输入比较冷启动和热运行,记录提示值、应用上限与浏览器版本。把结论写成可调整的配置,工作负载变化后重新测量。

来源

相关的浏览器能力决策可参考 WebAssembly 一致性指南和浏览器上下文容量规划指南。这些运营测量应与浏览器提供的粗粒度并发提示分开。

#hardwareConcurrency#Web Workers#浏览器性能#并发

让 BotBrowser 从研究走向生产

先用这些指南理解模型,再进入跨平台验证、隔离上下文和面向规模化的浏览器部署。