了解worker threads-node多线程-相关知识

基本使用

        对于cpu密集型可以通过worker_threads开启多线程优化,但是如果频繁创建和销毁也会很耗性能,所以官网说应该用线程池来优化下。

上面的示例为每个 parseJSAsync() 调用衍生工作线程。在实践中,为这些类型的任务使用工作线程池。否则,创建工作线程的开销可能会超过其收益。
The above example spawns a Worker thread for each parseJSAsync() call. In practice, use a pool of Workers for these kinds of tasks. Otherwise, the overhead of creating Workers would likely exceed their benefit.

worker_threads 工作线程 | Node.js v20 文档icon-default.png?t=N7T8https://nodejs.cn/api/worker_threads.html

主线程

        在主线程,worker_threads中引入isMainThread来判断是否为主线程。如果是主线程,我们就可以new Worker(src,{workerData})创建线程实例,给workerData属性赋值来传递数据,这样每个子线程都能通过workerData都能获取数据。

        调用线程实例的postMessage,会触发子线程的message事件,开始执行子线程的任务。

        我们监听线程实例的message和error方法,当子线程调用postMessage时(比如安排的任务完成)会触发主线程的message事件。

const express = require('express')
const { isMainThread, threadId, Worker } = require('worker_threads')

const app = express()
const port = 3232

app.get('/worker', (req, res) => {
  // 通过isMainThread判断是主线程还是工作线程
  if (isMainThread) {
    const worker = new Worker('./worker.js', { workerData: { data: '这是workerData传递的数据' } })

    // 向 Worker 线程发送数据//对象、字符串等都可以
    worker.postMessage({ data: '这是postMessage传递的数据' }) //workerData和postMessage传递的数据都会深拷贝

    // 监听来自 Worker 线程的消息
    worker.on('message', (message) => {
      console.log('从 Worker 接收到的消息:', message)
      res.send('message')

      setTimeout(() => {
        // 等会就关闭线程
        worker.terminate()
      }, 2000)
    })

    worker.on('error', (error) => {
      console.error('Worker error:', error)
      res.status(500).send('Internal Server Error')
    })

    worker.on('exit', (code) => {
      if (code !== 0) {
        console.error(`Worker stopped with exit code ${code}`)
      }
    })
  }
})

app.listen(port, () => {
  console.log(`Express app listening at http://localhost:${port}`)
})

子线程

        子线程能从worker_threads中拿到workerData,就是new Worker时传入的数据。

        如果子线程的任务处理完成,可以通过parentPort.postMessage(data),给主线程发消息。

        在子线程中引入的模块(比如下面的./store.js),会与主线程独立。

const { parentPort, workerData } = require('worker_threads')
const { arr } = require('./store.js')
// 监听来自主线程的消息
parentPort.on('message', (data) => {
  console.log('从主线程接收到的数据:', data)
  // 处理数据...
  arr.push(Date.now().toString().slice(-6))
  console.log(JSON.stringify(arr))
  console.log(workerData)

  // 向主线程发送消息
  setTimeout(() => {
    parentPort.postMessage({ result: '处理完成的数据' })
  }, 2000)
})

parentPort.on('error', (error) => {
  console.error(`Worker error: ${error}`)
})

parentPort.on('exit', (code) => {
  console.log(`Worker exited with code ${code}`)
})

子线程引入的文件 

        子线程引入了./store.js,在这个文件中能从worker_threads中拿到workerData。如果这个文件也引入其他文件,那其他文件同样与主线程独立,并且也能拿到workerData。

const { workerData, threadId } = require('worker_threads')
console.log(JSON.stringify(workerData), threadId, '开启了子线程')

module.exports = {
  arr: [1, 2, 3]
}

数据隔离

        在worker_threads中通过“深拷贝”实现了一定的变量隔离,有深拷贝的数据有new Worker是传入的workerData,以及postMessage时传递的消息等。

        因为每个子线程有自己的v8堆和调用栈,所以他的全局变量(global)和内存空间都是独立于主线程的。

内存共享-SharedArrayBuffer

        SharedArrayBuffer是一种特殊的 ArrayBuffer,它允许在不同的 Worker 线程(包括主线程和 worker_threads 中的 Worker 线程)之间共享内存数据。但是多个线程同时使用时要注意同步问题,避免竞态条件(如果程序运行顺序的改变会影响最终结果,这就是一个竞态条件。哈哈),并且曾经因为安全漏洞被多个平台禁用(哦。),现在可以用了。

        知道下有这样一个东西可以在线程之间共享内存。

        

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值