如何在Node.js中创建线程

106

有没有办法创建线程以同时运行多个方法?

这样,如果任何一个方法在中途失败,则应该杀死所有其他线程。

12个回答

106
新答案:虽然以前的Node.js无法本地使用线程,但现在已添加了这种能力。请查看https://nodejs.org/api/worker_threads.html获取详细信息。
旧答案:根据设计,每个Node.js进程都是单线程的。因此,要获得多个线程,您必须拥有多个进程(正如其他一些帖子提到的那样,还可以链接一些库,以便在Node中使用线程,但没有这样的功能。请参见Shawn Vincent的回答引用https://github.com/audreyt/node-webworker-threads)。
您可以从主进程启动子进程,如Node.js文档中所示:http://nodejs.org/api/child_process.html。 这个页面上的示例非常好,并且非常简单直观。
然后,您的父进程可以监视它启动的任何进程的关闭事件,然后可以强制关闭您启动的其他进程,以实现您正在谈论的一次失败全部停止的策略。
另请参阅:Node.js on multi-core machines

2
子进程独立于父进程。它们有自己的内存空间、PID和执行时间。不确定您所说的“顺序”是什么意思,但是是的,它们将并行运行,并由操作系统单独安排执行。 - Brian
如何将用户定义的函数作为子进程调用? - user87267867
我已经生成了许多子进程,代码如下:var spawn = require('child_process').spawn,newProcess1 = spawn('node', ['File1.js']),newProcess2 = spawn('node', ['File2.js']),newProcess3 = spawn('node', ['File3.js']); 它们将并行运行。如果 newProcess1 失败,则必须停止或杀死 newProcess2 和 newProcess3。 - user87267867
2
哦,我不知道那个库,但根据Alex Mills的评论,似乎你可以在Node中进行一些线程工作。话虽如此,下一个问题是你是否应该这样做……Node从一开始就被设计成让程序员摆脱线程带来的复杂性,但对于阻塞I/O却能产生类似的性能。我会编辑我的答案,以考虑到使用所引用的库是可能的这一事实。 - Brian
1
似乎这个答案已经过时了。 - danday74
显示剩余5条评论

34

3
应该是正确的。建议节点只能生成进程,而不能生成线程的答案是错误的。 - Alexander Mills

25

1
现在应该被接受为答案。 - danday74
@danday74,我添加了关于稳定性的新更新,似乎问题的所有者在SO上不活跃。唯一需要做的就是为了更多的可见性进行点赞。 - user158

10
您可以使用Napa.js来实现多线程。 https://github.com/Microsoft/napajs "Napa.js是一个基于V8构建的多线程JavaScript运行时,最初设计用于在Bing中开发高度迭代的服务,并具有非妥协性能。随着它的发展,我们发现它在CPU绑定任务中补充Node.js非常有用,具有在多个V8隔离中执行JavaScript并在它们之间通信的能力。 Napa.js作为Node.js模块公开,同时也可以嵌入到无Node.js依赖的主机进程中。"

7
我需要在Node.js中进行真正的多线程编程,threads包对我很有用。它会生成另一个进程,拥有自己的Node.js消息循环,因此它们不会相互阻塞。设置很容易,文档能够快速地让你上手。主程序和工作线程可以双向通信,并且如果需要,工作线程可以被终止。
由于多线程和Node.js是一个复杂且广泛讨论的话题,因此很难找到适合我的具体要求的软件包。以下对我没有用:
  • tiny-worker可以生成工作线程,但它们似乎共享相同的消息循环(但可能是我做错了什么 - threads有更多的文档,让我确信它真的使用了多个进程,所以我继续尝试直到它成功)
  • webworker-threads不允许在工作线程中使用require引入模块,而我需要这个功能

对于那些想知道我为什么需要真正的多线程的人:因为涉及到树莓派和中断的应用程序。一个线程处理这些中断,另一个线程负责存储数据(以及其他任务)。


2
我很欣赏你在这个答案中所付出的巨大思考! - MLissCetrus

5

nodejs 10.5.0版本发布,宣布在Node.js中引入了多线程。 这个功能仍处于实验阶段。现在有一个新的worker_threads模块可用。

如果您运行Node.js v10.5.0或更高版本,则可以开始使用工作线程,但这是一个实验性API。 它并不默认可用:您需要在调用Node.js时使用--experimental-worker进行启用。

以下是一个使用ES6和启用worker_threads的示例,在版本12.3.1上测试通过

//package.json

  "scripts": {
  "start": "node  --experimental-modules --experimental- worker index.mjs"
  },

现在,您需要从worker_threads中导入Worker。注意:为了支持ES6,您需要使用'.mjs'扩展名声明您的js文件。

//index.mjs
import { Worker } from 'worker_threads';

const spawnWorker = workerData => {
    return new Promise((resolve, reject) => {
        const worker = new Worker('./workerService.mjs', { workerData });
        worker.on('message', resolve);
        worker.on('error', reject);
        worker.on('exit', code => code !== 0 && reject(new Error(`Worker stopped with 
        exit code ${code}`)));
    })
}

const spawnWorkers = () => {
    for (let t = 1; t <= 5; t++)
        spawnWorker('Hello').then(data => console.log(data));
}

spawnWorkers();

最后,我们创建一个workerService.mjs。
//workerService.mjs
import { workerData, parentPort, threadId } from 'worker_threads';

// You can do any cpu intensive tasks here, in a synchronous way
// without blocking the "main thread"
parentPort.postMessage(`${workerData} from worker ${threadId}`);

输出:

运行 npm start

Hello from worker 4
Hello from worker 3
Hello from worker 1
Hello from worker 2
Hello from worker 5

2
这是你的文章吗:https://blog.logrocket.com/node-js-multithreading-what-are-worker-threads-and-why-do-they-matter-48ab102f8b10/? - serv-inc
不是这样的,虽然我之前确实参考过它。 - Priyesh Diukar

4

2

2
NodeJS现在包含线程(在回答时作为实验性功能)。

0

你可能正在寻找Promise.race(本地I/O竞速解决方案,而非线程)

假设你(或其他搜索此问题的人)想要比赛线程以避免失败并避免I/O操作的成本,这是一种简单且本地的方法来实现它(不使用线程)。Node旨在是单线程的(查找事件循环),因此尽可能避免使用线程。如果我的假设是正确的,我建议你使用Promise.racesetTimeout(链接中有示例)。使用此策略,您将比赛一系列承诺,每个承诺都尝试执行某些I/O操作,并在出现错误时拒绝该承诺(否则超时)。Promise.race语句在第一个解析/拒绝后继续执行,这似乎是您想要的。希望这能帮助到某些人!


2
这与线程无关,它们都在同一个线程中运行。 - Evan Carroll
@EvanCarroll - 感谢您提醒我表述不够清晰。我在前面加了一个假设,解释了为什么有人可能会查找线程竞争,并指出这使用了 Node 的事件循环中的 promises。如果您来自另一种语言,您很可能想要完成线程所做的事情,但还不熟悉事件循环或 promises。我想指出,如果您的目标是这样做,有更简单的方法可以实现。我添加了一个括号说明这不使用线程。如果这样能让您理解清楚,请告诉我。 - smileham
它似乎也回答了OP的标准:“如果任何方法在中途失败,所有其他线程都应该被终止”,所以我认为这是相关的。 - smileham
Promise.race按顺序执行所有的Promise,如果有异步操作(或async函数中的await),则在一个Promise完成后切换到另一个Promise。 - Nagabhushan Baddi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接