web worker数量是不是越多越好?

背景

一个CPU密集型的任务,如果可以用web worker并行处理,创建的Web Worker线程是否越多越好呢? 如果不是的话,创建多少个最合适呢?

实验

我们以用JS实现从1累加到100亿来模拟这个问题。

js 复制代码
// index.js
const num = 10000000000
let sum = 0
for(let i = 1; i < num; i++) {
    sum += i
}

上面的运算如何放在JS主线程里运行话,会造成阻塞。因此为了加速运算,需要开启web worker来并行处理。

  1. 新建多个web worker对象;
  2. 每个web worker只做一段数据的累加;
  3. 每当任意一个web worker运算完成之后,将值累加到一个全局变量上;
  4. 所有的web worker运算完成,则全局变量的值即为结果值。
js 复制代码
// index.js
const workerArray = [
  new Worker("worker.js"), 
  new Worker("worker.js"), 
  ...
]

let sum = 0 // 累加结果
let count = 0 // worker运行完成的个数
const startTimestamp = performance.now();

// 监听返回值
workerArray.forEach(item => {
    item.onmessage = function(event) {
        sum += event.data
        count++
        if(count === workArray.length) {
        // 当所有的worker运行完成
            const endTimestamp = performance.now()
            console.log(`Worker total sum: ${sum}, time cost: ${endTimestamp - startTimestamp}`)
        }
    }
})
 
// 调用worker.js进行运算
let start = 1 // 每个worker计算的起始值
const MAX_DURATION = Math.ceil(num / workerArray.length)
workerArray.forEach(item => {
    // 每个worker计算的结束值
    const end = Math.min(start + MAX_DURATION, num)
    item.postMessage({ start, end })
    start = end + 1 // 更新起始值
}); 

/////////////////////////////////
// worker.js
self.onmessage = function(event) {
  const start = event.data.start
  const end = event.data.end
  let sum = 0
  for(let i = start; i <= end; i++) {
    sum += i
  }
  self.postMessage(sum);
}

下图是我们运行多次的结果。x轴表示我们开启的web worker数量,y轴表示运行完获取总累加值需要的时间(ms)。

随着x值的增加,y值减少。当x到了一定值以后,y的减少就不明显了。这个值大概是6。

原因其实很简单,因为线程的并行需要依赖于CPU的核数。下图是我当前电脑的基本配置,可以看到一共有6个核。

查阅资料可以知道,可以通过APInavigator.hardwareConcurrency获取当前机器的CPU的逻辑核数。因此代码我们可以简单修改下:

js 复制代码
const workerArray = new Array(navigator.hardwareConcurrency).fill(new Worker('./worker.js'))

...
// 其他代码不变

结论

大部分需要通过web worker并行运算的场景下,JS主线程开启web worker的数量最好不要超过navigator.hardwareConcurrency的数量,否则过多的web worker不仅不能带来性能的提升,反而会增加额外通信和内存开销。

其他

代码地址:github.com/wdskuki/js-...

相关推荐
kyriewen13 小时前
我手写了一个 EventEmitter,面试官追问了 6 个问题——第 4 个我没答上来
前端·javascript·面试
IT_陈寒13 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
小林攻城狮14 小时前
使用 Transport 节流解决 Vercel AI SDK 流式渲染卡死问题
前端·react.js
前端缘梦14 小时前
告别 TS 运行时类型漏洞!Zod 完整入门实战教程(前端 / 全栈必备)
前端·react.js·全栈
the_answer14 小时前
Webpack vs Vite 深度对比分析
前端·webpack
转转技术团队15 小时前
验证码识别实战:前端不写页面,改训模型了?
前端
MomentYY15 小时前
Temperature:AI 的“脑洞旋钮”
前端·llm·ai编程
远航_15 小时前
OpenSpec 完整详细介绍
前端·后端
召钱熏15 小时前
状态枚举正确≠渲染正确:一个语音按钮的状态机边界修复实录
android·前端
SkyWalking中文站15 小时前
认识 Horizon UI · 1/17:SkyWalking 新一代可观测性控制台
运维·前端·监控