node多线程实现,node js 多线程

  node多线程实现,node js 多线程

  异步计算怎么做?下面这篇文章介绍了利用浏览器和Node.js的多线程能力进行异步计算的方法,希望对你有所帮助!

  node.js速度课程简介:进入学习

  都说Node.js可以实现高性能服务器,那么什么是高性能呢?

  所有的软件代码最终都要通过CPU来运行。CPU能否高效使用是区分性能高低的标志,也就是说不能闲置。[推荐研究:《nodejs 教程》]

  什么时候会闲置?

  当程序在做网络和磁盘IO的时候,CPU是空闲的,也就是空转。多核CPU可以同时运行多个程序。如果只使用一个内核,则其他内核处于空闲状态。因此,为了实现高性能,我们必须解决这两个问题。

  操作系统提供了线程的抽象,不同代码对应的执行分支都可以同时运行在不同的CPU上,这是一种利用众多核心CPU性能的方式。

  但是如果有些线程在进行IO,也就是等待读写完成被阻塞,这是一种相对低效的方式,所以操作系统实现了DMA的机制,也就是设备控制器,由硬件负责从设备到内存的传输,完成后告诉CPU。这样,当一些线程处于IO时,可以挂起线程,然后在收到DMA传输数据完成的通知后继续运行。

  多线程,DMA,这是操作系统提供的一种解决方案,它利用众核CPU来解决CPU拥塞等IO问题。

  而且各种编程语言都封装了这个机制,Node.js也是,Node.js之所以性能高,是因为异步IO的设计。

  Node.js的异步IO是在libuv中实现的,基于操作系统提供的异步系统调用,一般是硬件层面的异步,比如DMA来传输数据。但是有些同步的系统调用被libuv封装后会变成异步的。这是因为libuv中有一个线程池来执行这些任务,并使同步API异步。这个线程池的大小可以通过UV_THREADPOOL_SIZE的环境变量来设置,默认值是4。

  我们在代码中调用的许多异步API都是通过线程实现的。

  例如:

  const fsPromises=require(fs )。承诺;

  const data=await fs promises . readfile(。/filename’);但是这个异步API只是解决了IO的问题,那么如何利用多核CPU的优势做计算呢?

  Node.js在10.5中实验性的引入了worker_thread模块(12年正式引入),可以创建线程,最后用多个CPU运行。这是使用多核CPU进行计算的方式。

  异步API可以使用多线程做IO,而worker_thread可以创建线程做不同用途的计算。

  要说清楚worker_thread,我们得从浏览器的web worker说起。

  

浏览器的 web worker

  浏览器也面临着无法使用多核CPU做计算的问题,所以html5引入了web worker,可以通过另一个线程做计算。

  !声明文档类型

  超文本标记语言

  头/头

  身体

  脚本

  (异步函数(){

  const res=await runCalcWorker(2,3,3,3);

  console . log(RES);

  })();

  函数runCalcWorker(.nums) {

  返回新承诺((解决,拒绝)={

  const calcWorker=新工人(。/web worker . js’);

  calcWorker.postMessage(nums)

  calc worker . on message=function(msg){

  resolve(msg . data);

  };

  calc worker . on error=reject;

  });

  }

  /脚本

  /body

  /html我们创建一个Worker对象,指定在另一个线程中运行的js代码,然后通过postMessage向其传递消息,通过onMessage接收消息。这个过程也是异步的,我们进一步把它封装成promise。

  然后接收webWorker.js中的数据,进行计算,然后通过postMessage返回结果。

  //webWorker.js

  onmessage=function(msg) {

  if (Array.isArray(msg.data)) {

  const RES=msg . data . reduce((total,cur)={

  return total=cur

  }, 0);

  后期消息(RES);

  }

  }就这样,我们用了另一个CPU核来运行这个计算,和普通异步代码写代码没什么区别。但这个异步其实不是IO的异步,而是计算的异步。

  Node.js的Worker thread类似于web worker,我甚至怀疑worker thread的名字是受了web worker的影响。

  

Node.js 的 worker thread

  如果在Node.js中实现上述异步计算逻辑,它是这样的:

  const runCalcWorker=require(。/runCalcWorker’);

  (异步函数(){

  const res=await runCalcWorker(2,3,3,3);

  console . log(RES);

  })();异步调用,因为异步计算和异步IO在用法上没有区别。

  //runCalcWorker.js

  const { Worker }=require( Worker _ threads );

  module.exports=函数(.nums) {

  返回新承诺(功能(解决,拒绝){

  const calcWorker=新工人(。/nodeworker . js’);

  calc worker . postmessage(nums);

  calcWorker.on(message ,resolve);

  calcWorker.on(错误,拒绝);

  });

  }然后异步计算是通过创建一个Worker对象,指定在另一个线程中运行的JS,然后通过postmessage传递消息,通过message接收消息来实现的。这与web worker非常相似。

  //nodework . js

  常数{

  父端口

  }=require( worker _ threads );

  parentPort.on(message ,(data)={

  const res=data.reduce((total,cur)={

  return total=cur

  }, 0);

  parent port . postmessage(RES);

  });在执行计算的nodeWorker.js中,监听消息message,然后计算并通过parentPost.postMessage返回数据

  与网络工作者相比,你会发现一些特别的东西。所以我认为Node.js的worker thread的api是参考web worker设计的。

  然而,实际上worker thread在创建时也支持通过wokerData进行数据传输:

  const { Worker }=require( Worker _ threads );

  module.exports=函数(.nums) {

  返回新承诺(功能(解决,拒绝){

  const calcWorker=新工人(。/nodework . js ,{

  workerData: nums

  });

  calcWorker.on(message ,resolve);

  calcWorker.on(错误,拒绝);

  });

  }然后工作线程通过workerData处理它:

  常数{

  parentPort,

  工人数据

  }=require( worker _ threads );

  const data=workerData

  const res=data.reduce((total,cur)={

  return total=cur

  }, 0);

  parent port . postmessage(RES);因为有传递消息的机制,所以不能序列化的数据(如函数)不能被传输进行序列化和反序列化。这也是worker thread的特点。

  

Node.js 的 worker thread 和 浏览器 web woker 的对比

  从使用的角度来说,可以封装成普通的异步调用,和其他异步API没什么区别。

  都需要序列化和反序列化,都支持postMessage和onMessage发送和接收消息。

  除了message,Node.js的worker线程还支持更多传输数据的方式,比如workerData。

  但本质上两者都是为了实现异步计算,充分利用多核CPU的性能。没有区别。

  

总结

  高性能程序要充分利用CPU资源,不要让它闲置,也就是不要让CPU等待IO,多核CPU要能同时利用它做计算。操作系统提供了线程和DMA机制来解决这个问题。Node.js也做了相应的封装,也就是libuv实现的异步IO的api。然而,计算的异步是由节点12,即工作线程正式引入的。api设计指的是浏览器的web worker。通过postMessage和onMessage传递消息时需要对数据进行序列化,所以不能传递函数。

  从使用的角度来看,异步计算和异步IO的使用方式是一样的,但异步IO只是让cpu在不同的块中等待IO完成。异步计算利用多核CPU同时进行并行计算,计算性能提升数倍。

  有关编程的更多信息,请访问:编程视频!以上是讲如何利用Node.js的多线程能力做异步计算的细节,更多请关注我们的其他相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: