加入收藏 | 设为首页 | 会员中心 | 我要投稿 核心网 (https://www.hxwgxz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

Node.js多线程完全指南

发布时间:2019-03-29 23:34:32 所属栏目:建站 来源:疯狂的技术宅
导读:很多人都想知道单线程的 Node.js 怎么能与多线程后端竞争。考虑到其所谓的单线程特性,许多大公司选择 Node 作为其后端似乎违反直觉。要想知道原因,必须理解其单线程的真正含义。 JavaScript 的设计非常适合在网上做比较简单的事情,比如验证表单,或者说

使用 port 在线程之间进行通信的方法有两种。第一个是默认值,这个方法比较容易。在 worker 的代码中,我们从worker_threads 模块导入一个名为 parentPort 的对象,并使用对象的 .postMessage() 方法将消息发送到父线程。

这是一个例子:

  1. import { parentPort } from 'worker_threads';  
  2. const data = {  
  3.  // ...  
  4. };  
  5. parentPort.postMessage(data); 

parentPort 是 Node.js 在幕后创建的 MessagePort 实例,用于与父线程进行通信。这样就可以用 parentPort 和 worker 对象在线程之间进行通信。

线程间的第二种通信方式是创建一个 MessageChannel 并将其发送给 worker。以下代码是如何创建一个新的 MessagePort 并与我们的 worker 共享它:

  1. import path from 'path';  
  2. import { Worker, MessageChannel } from 'worker_threads';  
  3. const worker = new Worker(path.join(__dirname, 'worker.js'));  
  4. const { port1, port2 } = new MessageChannel();  
  5. port1.on('message', (message) => {  
  6.  console.log('message from worker:', message);  
  7. });  
  8. worker.postMessage({ port: port2 }, [port2]); 

在创建 port1 和 port2 之后,我们在 port1 上设置事件监听器并将 port2 发送给 worker。我们必须将它包含在 transferList 中,以便将其传输给 worker 。

在 worker 内部:

  1. import { parentPort, MessagePort } from 'worker_threads';  
  2. parentPort.on('message', (data) => {  
  3.  const { port }: { port: MessagePort } = data;  
  4.  port.postMessage('heres your message!');  
  5. }); 

这样,我们就能使用父线程发送的 port 了。

使用 parentPort 不一定是错误的方法,但最好用 MessageChannel 的实例创建一个新的 MessagePort,然后与生成的 worker 共享它。

请注意,在后面的例子中,为了简便起见,我用了 parentPort。

使用 worker 的两种方式

可以通过两种方式使用 worker。第一种是生成一个 worker,然后执行它的代码,并将结果发送到父线程。通过这种方法,每当出现新任务时,都必须重新创建一个工作者。

第二种方法是生成一个 worker 并为 message 事件设置监听器。每次触发 message 时,它都会完成工作并将结果发送回父线程,这会使 worker 保持活动状态以供以后使用。

Node.js 文档推荐第二种方法,因为在创建 thread worker 时需要创建虚拟机并解析和执行代码,这会产生比较大的开销。所以这种方法比不断产生新 worker 的效率更高。

这种方法被称为工作池,因为我们创建了一个工作池并让它们等待,在需要时调度 message 事件来完成工作。

以下是一个产生、执行然后关闭 worker 例子:

  1. import { parentPort } from 'worker_threads';  
  2. const collection = [];  
  3. for (let i = 0; i < 10; i += 1) {  
  4.  collection[i] = i;  
  5. }  
  6. parentPort.postMessage(collection); 

将 collection 发送到父线程后,它就会退出。

下面是一个 worker 的例子,它可以在给定任务之前等待很长一段时间:

  1. import { parentPort } from 'worker_threads';  
  2. parentPort.on('message', (data: any) => {  
  3.  const result = doSomething(data);  
  4.  parentPort.postMessage(result);  
  5. }); 

worker_threads 模块中可用的重要属性

worker_threads 模块中有一些可用的属性:

isMainThread

当不在工作线程内操作时,该属性为 true 。如果你觉得有必要,可以在 worker 文件的开头包含一个简单的 if 语句,以确保它只作为 worker 运行。

  1. import { isMainThread } from 'worker_threads';  
  2. if (isMainThread) {  
  3.  throw new Error('Its not a worker');  

workerData

产生线程时包含在 worker 的构造函数中的数据。

  1. const worker = new Worker(path, { workerData }); 

(编辑:核心网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读