在node.js上进行并发任务,使用Fibers、Web-workers还是Threads更好?

114
我之前偶然发现了node.js,很喜欢它。但很快我就发现它非常缺乏执行CPU密集型任务的能力。于是我开始搜索并得到了以下解决方案:Fibers,Webworkers和Threads(thread-a-gogo)。现在,该使用哪一个让我感到困惑,而且其中一个肯定需要被使用 - 毕竟拥有一个只擅长IO而不擅长其他的服务器有什么意义呢?请给些建议!
更新:
我最近想到了一种方法,只需要建议即可。我的想法是这样的:让我们使用一些线程(使用thread_a_gogo或者可能是webworkers)。现在,当我们需要更多线程时,我们可以创建更多。但是会有一些限制,因为创建过程会使开销增加。当我们超过限制时,我们可以fork一个新的节点,并开始在其上创建线程。这样,它可以一直进行,直到达到某个限制(毕竟进程也有很大的开销)。当达到此限制时,我们开始排队任务。每当有空闲的线程时,它将被分配一个新任务。这样,它可以顺利进行。
所以,这就是我想的。这个想法好吗?我对所有这些进程和线程的东西都比较陌生,所以没有任何专业知识。请分享您的意见。
谢谢。 :)

请注意:Workers 是一种浏览器规范,不是 Javascript 的功能。 - FredTheWebGuy
好的,我明白了。我的问题是关于node.js - 服务器端代码,而不是客户端! - Parth Thakkar
只是澄清一下- 我看到原始问题是关于 NodeJs 中的 WebWorker,这是不可能的- NodeJs 使用“线程”。但是,有一个在 NodeJs 运行时内允许使用 WebWorker 语法的 NodeJS 模块。 - FredTheWebGuy
7个回答

335
Node具有完全不同的范例,一旦正确掌握,便更容易看到这种不同的解决问题方式。您永远不需要在Node应用程序中使用多个线程(1),因为您有一种不同的做事方式。您创建多个进程;但它与Apache Web服务器的Prefork mpm的工作方式非常非常不同。
现在,让我们想象我们只有一个CPU核心,并且我们将开发一个应用程序(以Node的方式)来完成一些工作。我们的工作是处理一个大文件,逐字节运行其中的内容。对于我们的软件来说,最好的方法是从文件开头开始工作,按字节跟随到结尾。
-- 嗨,Hasan,我猜你要么是新手,要么是我祖父那个时代的老派人物!!! 为什么不创建一些线程,让它快得多呢?
- -哦,我们只有一个CPU核心。
-- 那又怎样?创建一些线程,让它更快!
-- 不是这样的。如果我创建线程,那么速度会变慢。因为我会向系统添加大量开销以在线程之间切换,试图给它们恰当的时间,并在我的过程中试图在这些线程之间通信。除了所有这些事实外,我还必须考虑如何将单个任务分成多个可以并行完成的部分。
-- 好的好的,我明白你很穷。让我们使用我的电脑,它有32个核心!
--哇,你太棒了,亲爱的朋友,非常感谢你。我很感激!
然后我们回到工作中。现在我们有32个CPU核心,这要归功于我们富有的朋友。我们必须遵守的规则已经改变。现在我们想利用得到的所有财富。
要使用多个核心,我们需要找到一种将工作分成可以并行处理的片段的方法。如果不是Node,我们会使用线程;32个线程,每个CPU核心一个。然而,既然我们有了Node,我们将创建32个Node进程。
线程可能是Node进程的一个很好的替代品,甚至可能是一种更好的方式;但只适用于一类特定的工作,其中工作已经定义好了,我们完全控制如何处理它。除此之外,对于其他任何来自外部的问题,我们无法控制工作方式并且想要尽快回答的问题,Node的方式无疑是优越的。
-- 嗨,Hasan,你还在单线程工作吗?你怎么了,伙计?我给你提供了你想要的东西。你再也没有借口了。创建线程,让它运行得更快。
-- 我已将工作分成了多个部分,每个进程都会并行处理其中的一个部分。
-- 为什么不创建线程?
-- 抱歉,我认为这是不可用的。如果你愿意,可以拿走你的电脑吗?
-- 不,好的,我很酷,我只是不明白为什么你不使用线程?
--谢谢你提供的计算机。 :)我已将工作分成多个部分,并创建了进程以并行处理这些部分。所有CPU核心都将得到充分利用。我也可以使用线程来完成这项工作;但是Node有自己的方法,而我的老板Parth Thakkar希望我使用Node。
--好的,如果你需要另一台计算机,请告诉我。:p --如果我创建33个进程而不是32个,则操作系统的调度程序将暂停一个线程,启动另一个线程,在一些周期后再次暂停它,然后再启动另一个线程......这是不必要的开销。我不希望出现这种情况。实际上,在一个有32个内核的系统上,我甚至不想创建32个进程,31个进程可能会更好。因为不仅是我的应用程序会在这个系统上工作。留出一些空间给其他程序可能是有好处的,特别是如果我们有32个房间。
--我相信我们现在对于充分利用处理器进行CPU密集型任务已经达成了共识。
--嗯,Hasan,对于我有点嘲笑你,我感到很抱歉。我相信我现在更好地理解你了。但仍有一些事情需要解释:大量运行线程的热潮是什么?我到处都看到线程比分叉进程更快、更简单?你使用进程而不是线程来分叉,认为Node的性能已经达到了最高点。那么Node是否不适合这种工作?
--没问题,我很冷静。每个人都这样说,所以我觉得我已经习惯了这种听话。
--那么?Node不适合这个吗?
--即使线程也很好,但是对于线程/进程创建开销;在你重复许多次的事情上,每毫秒都很重要。但是,我仅创建32个进程,这将需要极少量的时间。它只会发生一次。这并不会造成任何影响。
--那么何时需要创建数千个线程?
--你永远不需要创建数千个线程。但是,在处理来自外部的工作的系统上,如处理HTTP请求的Web服务器;如果您为每个请求使用一个线程,则会创建大量线程,其中许多线程是无用的。
--但Node不同?对吧?
--是的,正是如此。这就是Node真正出色的地方。就像线程比进程轻,函数调用比线程轻。Node调用函数,而不是创建线程。在Web服务器的例子中,每个传入的请求都会引起一个函数调用。
--嗯,有趣;但如果您不使用多个线程,一次只能运行一个函数,当许多请求同时到达Web服务器时,如何处理?
-- 你关于函数运行的说法是完全正确的,一次只能运行一个函数,永远不会同时运行两个函数。也就是说,在单个进程中,一次只能运行一个代码范围。除非操作系统调度程序暂停该函数并切换到另一个函数,否则不会暂停该函数并切换到另一个函数,除非暂停该进程以给另一个进程(而不是我们进程中的另一个线程)留出时间。(2)
-- 那么进程如何处理两个请求?
-- 只要我们的系统有足够的资源(RAM、网络等),进程就可以同时处理成千上万个请求。这些函数的运行方式是关键的区别。
-- 嗯,现在我应该感到兴奋吗?
-- 可能 :) Node在队列上运行循环。在这个队列中,我们的工作是我们开始处理传入请求的调用。这里最重要的一点是我们设计函数运行的方式。我们不会像其他人一样开始处理请求,并让调用者等待直到我们完成工作,而是在完成了可接受的工作后迅速结束我们的函数。当我们需要等待另一个组件执行一些工作并返回值时,我们不会等待它,而是简单地完成我们的函数,将其余的工作添加到队列中。
-- 听起来太复杂了吗?
-- 不不,我可能听起来很复杂,但这个系统本身非常简单,而且非常有道理。
现在我想停止引用这两个开发人员之间的对话,并在最后快速举一个例子来说明这些函数如何工作。
通过这种方式,我们正在做操作系统调度程序通常会做的事情。我们在某个时刻暂停我们的工作,让其他函数调用(例如多线程环境中的其他线程)运行,直到我们再次轮到我们为止。这比将工作留给操作系统调度程序要好得多,后者试图为系统上的每个线程提供时间。我们比操作系统调度程序更清楚自己在做什么,并且我们应该在应该停止的时候停止。
下面是一个简单的示例,我们打开一个文件并读取它以对数据进行一些处理。
同步方式:
Open File
Repeat This:    
    Read Some
    Do the work

异步方式:

Open File and Do this when it is ready: // Our function returns
    Repeat this:
        Read Some and when it is ready: // Returns again
            Do some work

正如你所看到的,我们的函数要求系统打开一个文件,并且不等待它被打开。当文件准备好后,它会提供下一步操作并自行完成。当我们返回时,Node会在队列上运行其他函数调用。在运行完所有函数后,事件循环会移动到下一个轮回...
总之,Node有一个完全不同于多线程开发的范式,但这并不意味着它缺少功能。对于同步作业(我们可以决定处理顺序和方式),它的性能与多线程并行一样好。对于来自外部的作业,例如对服务器的请求,它更加优越。
(1) 除非你正在构建其他语言的库,比如C/C++,否则你仍然不需要创建线程来分割任务。对于这种工作,你有两个线程,其中一个将继续与Node通信,而另一个则执行实际工作。
(2) 实际上,每个Node进程都有多个线程,原因如我在第一个脚注中提到的那样。然而,这绝不像1000个线程做类似的工作。这些额外的线程是用来接受IO事件和处理进程间消息传递等事务的。
更新(作为对评论中一个好问题的回复)
@Mark,感谢您的建设性批评。在Node的范式中,除非队列中的所有其他调用都被设计为一个接一个地运行,否则不应该有需要太长时间来处理的函数。对于计算开销大的任务,如果我们从整体上看这个问题,我们会发现这不是一个“我们应该使用线程还是进程”的问题,而是一个“我们如何将这些任务以平衡的方式分成子任务,以便我们可以在系统上利用多个CPU核心并行运行它们?”的问题。假设我们要在一个有8个核心的系统上处理400个视频文件。如果我们想一次只处理一个文件,那么我们需要一个系统,它会处理同一文件的不同部分,在这种情况下,也许一个多线程单进程系统会更容易构建,甚至更高效。我们仍然可以通过运行多个进程并在必要时在它们之间传递消息来使用Node进行此操作。正如我之前所说的,对于这种类型的任务,Node的多进程方法与多线程方法一样好;但不会更好。再次强调,Node闪耀的情况是当这些任务作为输入同时从多个源流入系统时,因为在Node中保持许多连接并发相比于每个连接一个线程或一个进程系统更轻量级。
关于setTimeout(...,0)调用; 有时在耗时的任务中给予一些休息,以允许队列中的调用有机会进行处理是必要的。将任务划分为不同的方式可以使您免受这些问题的困扰;但是,这并不是一种真正的技巧,它只是事件队列工作的方式。此外,为了实现这个目的,使用process.nextTick更好,因为当您使用setTimeout时,需要计算和检查经过的时间,而process.nextTick就是我们真正想要的:“嘿,任务,回到队列末尾,你已经用完你的份额了!”

10
太棒了!真的太棒了!我喜欢你回答这个问题的方式! :) - Parth Thakkar
50
我真的无法相信世上居然有极其刻薄的人在对这篇回答文章进行投票!问者称之为“太棒了!”一个书籍作者在看到此后还邀请我在他的网站上写作;但是一些天才们却给它投了反对票。为什么你不分享自己聪明的智力素质并评论它,而非卑鄙地偷偷地给它投反对票呢?为什么一些好东西会让你如此不安?为什么你想阻止别人从中获益? - hasanyasin
10
这不是完全公正的回答。那么对于计算成本高的任务呢,我们无法"快速结束"函数调用怎么办?我相信有些人会使用一些setTimeout(...,0)的技巧来解决,但在这种情况下使用单独的线程肯定更好? - mpen
3
@hasanyasin 这是我迄今为止发现的关于node最清晰的解释! :) - Venemo
7
通常情况下,如果计算成本很高,可以选择使用线程/进程工作者的选项/模块... 对于这些类型的事情,我通常使用消息队列,并有工作进程从队列中处理一个任务,并处理该任务。这还允许扩展到多个服务器。类似地,Substack有很多模块专门用于配置和扩展,你可以查看一下。 - Tracker1
显示剩余21条评论

35

(2016年更新:Web Workers正在进入io.js - Node.js的分支 Node.js v7 - 请见下文。)

(2017年更新:Web Workers不会进入Node.js v7或v8 - 请见下文。)

(2018年更新:Web Workers将进入Node.js Node v10.5.0 - 请见下文。)

一些澄清

阅读以上答案后,我想指出,就JavaScript和Node在并发方面的哲学而言,Web Workers中没有任何违反该哲学的东西。(如果有的话,它甚至不会被WHATWG讨论,更不用说在浏览器中实现了)。

您可以将Web Worker视为轻量级微服务,以异步方式访问。不共享状态。不存在锁定问题。没有阻塞。不需要同步。就像当您从Node程序使用RESTful服务时,您不必担心它现在是“多线程”的,因为RESTful服务不在与您自己的事件循环相同的线程中。它只是一个单独的服务,您可以异步访问,这才是最重要的。

与Web Workers类似。它只是一个用于与在完全分离的上下文中运行的代码通信的API,无论它是在不同的线程、进程、cgroup、区域、容器或不同的机器上运行都完全无关紧要。这是因为它具有严格的异步、非阻塞API,并且所有数据都通过值传递。事实上,Web Workers在概念上非常适合Node,而许多人并不知道Node实际上相当大量地使用了线程,并且实际上“除了你的代码,一切都在并行运行”-请参见:

但是Web Workers甚至不需要使用线程来实现。你可以使用进程、绿色线程,甚至是云中的RESTful服务,只要使用Web Worker API即可。消息传递API的整个美妙之处在于,由于并发模型的细节不会被暴露出来,因此底层实现基本上是无关紧要的。

一个单线程事件循环非常适合I/O密集型操作。对于CPU密集型操作,特别是长时间运行的操作,它并不那么有效。为此,我们需要生成更多进程或使用线程。以可移植的方式管理子进程和进程间通信可能相当困难,而使用线程意味着处理锁定和同步问题,这些问题很难正确处理。
通常建议将长时间运行的CPU密集型操作分成较小的任务(类似于我的回答中加速setInterval的示例),但这并不总是实际的,并且它不会使用多个CPU核心。
我写这篇文章是为了澄清基本上表明Web Workers是为浏览器而创建的评论(忘记了JavaScript中几乎可以说所有东西都是如此)。
Node模块
有一些模块被认为是为Node添加Web Workers的: 我没有使用过它们,但是有两个快速观察结果可能是相关的:截至2015年3月,node-webworker已经4年没有更新了,而node-webworker-threads则在一个月前进行了更新。此外,在node-webworker-threads使用示例中,您可以将函数作为Worker构造函数的参数之一,这似乎可能会引起微妙的问题,如果它是使用共享内存的线程实现的话(除非该函数仅用于其.toString()方法,并且在其他环境中编译,否则可能会有问题 - 我必须更深入地研究一下,只是在这里分享我的观察)。如果有任何其他实现Web Workers API的相关项目,请留言。
更新1
我写这篇答案时还不知道,但恰好在我写这篇答案的前一天,io.js添加了Web Workers

(io.js是Node.js的一个分支 - 有关更多信息,请参见Mikeal Rogers的InfoWorld采访:为什么io.js决定分叉Node.js。)

它不仅证明了web workers在JavaScript和Node中关于并发性方面的哲学没有任何违背,而且可能会使web workers成为服务器端JavaScript(如io.js和可能的Node.js)中的一流公民,就像它已经是客户端JavaScript 在所有现代浏览器中

更新2

在更新1和我的推文中,我提到了io.js pull request #1159,现在重定向到Node PR #1159,该请求已于7月8日关闭,并替换为仍然开放的Node PR#2133。在这些拉取请求下正在进行一些讨论,可能会提供有关io.js / Node.js中Web工作者状态的更多最新信息。

最新信息 - 感谢NiCk Newman在评论中发布此信息:2015年9月6日,Petka Antonov提交了工人:初始实现,可以下载并尝试在此树中。有关详细信息,请参见NiCk Newman的评论

更新4

截至2016年5月,仍然开放的PR#2133 - workers:initial implementation上最后的评论已经有3个月了。 5月30日,Matheus Moreira要求我在下面的评论中发布更新,并在PR评论中要求此功能的当前状态
PR讨论的第一个回答持怀疑态度,但后来Ben Noordhuis 写道:“将其以一种形式合并到v7是我待办事项清单上的任务。”
所有其他评论似乎都赞同这一点,截至2016年7月,Web Workers应该可以在下一个版本的Node(即计划于2016年10月发布的版本7.0)中使用,但不一定采用此确切的PR形式。

感谢Matheus Moreira在评论中指出并在GitHub上重新讨论此事。

更新5

截至2016年7月,npm上有一些以前不可用的模块-有关相关模块的完整列表,请搜索npm以获取workers、web workers等。如果有任何特殊情况,请发表评论。

更新6

截至2017年1月,Web Workers不太可能合并到Node.js中。

Petka Antonov于2015年7月8日提交的拉取请求#2133 workers:initial implementation 最终由Ben Noordhuis于2016年12月11日关闭,他评论说,“多线程支持增加了太多的新故障模式,而效益却不足”,“我们也可以使用更传统的方法,如共享内存和更有效的序列化来实现它。”

更多信息请参见GitHub上PR 2133的评论。

再次感谢Matheus Moreira在评论中指出这一点。

更新6

我很高兴地宣布,几天前,在2018年6月,Web Workers作为实验性功能出现在Node v10.5.0中,并通过--experimental-worker标志进行激活。

有关更多信息,请参见:

终于!我可以更新三年前的Stack Overflow答案了,其中我认为像Web Workers一样进行线程处理并不违背Node的理念,只是这次我要说我们终于做到了!


1
@NiCkNewman 谢谢。我看到io.js中的原始拉取请求现在已关闭,并被另一个替换了 - 在GitHub上的拉取请求评论中有一些讨论,也许你能在那里找到一些信息。请参见:我的答案中的更新2。 - rsp
1
是的,看起来他们刚刚修复了最后一个 libuv 问题。我想知道什么时候我可以得到这个模块。迫不及待!感谢您的更新~编辑:刚刚被初始化:https://github.com/petkaantonov/io.js/commit/ea143f72fc6845668716bd7a5da22771011defe4 就是这样,它即将到来! - NiCk Newman
1
是的,它已经上线了。(尚未正式实施),但您可以在此处下载源代码:https://github.com/petkaantonov/io.js/tree/ea143f72fc6845668716bd7a5da22771011defe4,如果您想测试它,可以编译!我正在进行。~ - NiCk Newman
1
@NiCkNewman 谢谢你提供的新信息 - 我已经将它添加到答案中了。 - rsp
1
@MatheusMoreira 感谢您的评论,特别感谢您在 GitHub 上重新引发了讨论。看起来 Web Workers 将会出现在 Node v7 中 - 我已经更新了我的回答,如果有任何需要纠正的地方,请告诉我。谢谢。 - rsp
显示剩余5条评论

8
我来自旧思想的学派,我们使用多线程来使软件运行更快。过去的三年里,我一直在使用Node.js,并且是它的热情支持者。正如hasanyasin详细解释了node的工作原理和异步功能的概念。但是让我在这里补充一些东西。
早期,由于单核心和较低的时钟速度,我们尝试各种方法使软件工作得更快和并发。在DOS时代,我们每次只运行一个程序。然后在Windows中,我们开始同时运行多个应用程序(进程)。测试了抢占式和非抢占式(或合作式)等概念。现在我们知道,抢占式是单核计算机更好的多处理任务的答案。接着出现了进程/任务和上下文切换的概念。然后出现了线程的概念,以进一步减轻进程上下文切换的负担。线程被称为生成新进程的轻量级替代品。
因此,无论您是否喜欢信号线程或不使用多核心或单核心,您的进程都将被操作系统抢占和时间分片。
Node.js是单个进程,提供异步机制。这里的任务分派到底层操作系统执行任务,而我们在事件循环中等待任务完成。一旦我们得到操作系统的信号,我们就可以执行我们需要做的事情。现在,在某种程度上,这是合作式/非抢占式多任务处理,因此我们不应该长时间阻塞事件循环,否则我们的应用程序将迅速降级。
因此,如果有任何阻塞性质的任务或非常耗时的任务,我们必须将其分支到抢占式OS和线程的世界中。 在libuv文档中有很好的例子。另外,如果您进一步阅读文档,您会发现文件I/O在node.js中是在线程中处理的
首先,这完全取决于我们软件的设计。其次,无论他们告诉你什么,上下文切换总是在发生。线程一直存在并且仍然存在的原因是它们比进程更快地在之间切换。 在node.js的幕后,所有东西都是c++和线程。Node提供了扩展其功能并通过使用线程在必要时进一步加速的c++方法,例如阻塞任务,如从源读取、写入源、大数据分析等等。
我知道hasanyasin的答案是被接受的,但对我来说,无论你说什么或如何将它们隐藏在脚本后面,线程都将存在。其次,没有人仅仅为了速度将任务拆分成线程,这主要是针对阻塞任务而言。线程是Node.js的骨干,因此在完全抨击多线程之前是不正确的。此外,线程与进程的限制并不完全适用于每个核心的节点进程数量,线程就像进程的子任务。实际上,线程比进程更轻量级,不会出现在Windows任务管理器或Linux top命令中。

异步代码并不是什么巨大的创新(实际上我们已经有了几十年),而多线程也不是一种被替换的过时技术。它们是具有不同权衡的不同工具,事实上它们甚至可以很好地结合起来。每次运行 node-cluster 时,实际上会运行多个“线程”(在这种情况下是进程,但是使用线程也可以实现,并且更加轻量级)。或者以 Erlang 或 Go 为例,它们可以运行数千个绿色线程... - Hejazzman
我认为我们忽略的主要点是,操作系统下的进程始终以抢占方式进行,以提供公平性。此外,使用多处理器可以实现实际的并行代码执行,但即使如此,也会发生抢占。异步工作也是由操作系统以某种形式的进程来完成的。 - limplash

4

我不确定在这种情况下是否需要webworkers,因为它们是客户端技术(在浏览器中运行),而node.js运行在服务器上。就我所知,纤程也是阻塞的,即它们是自愿多任务处理的,因此您可以使用它们,但应该通过yield自己管理上下文切换。线程可能是您实际需要的,但我不知道它们在node.js中有多成熟。


3
仅供参考,WebWorker已(部分地)适用于Node.js,并可作为“node-workers”包使用。请查看此链接:https://github.com/cramforce/node-worker - Parth Thakkar
好知道,谢谢。不过文档非常缺乏,我不知道它是在单独的线程、进程中运行,还是仅在同一进程中运行,而且我没有时间深入代码,所以我不知道它是否适用于你的情况。 - lanzz
@ParthThakkar:那个项目已经三年没有动过了(你发布时是两年),并且还没有超过0.0.1版本。 - mpen
@Mark:我对此一无所知的原因是我还不是专业程序员。我甚至还没有进入大学。我仍然是一名高中生,除了管理学校工作外,还在阅读有关编程的内容。因此,我不可能对所有这些问题都有所了解。我只是发表了我所知道的内容... - Parth Thakkar
@ParthThakkar:我不是在责怪你,我只是说其他人应该注意使用这样一个不成熟的项目。我所知道的另一个线程库是 "threads a gogo",它也没有得到更多的活动。在选择库时,我喜欢确保它们正在积极开发,否则它们很可能会不完整,并且如果有任何错误,它们很可能不会得到解决。更不用说它们可能也落后于时代。 - mpen
显示剩余3条评论

3

worker_threads 已经在 node@10.5.0 版本中实现并通过标志进行了发布。这仍然是一个初始实现版本,在未来的发布中需要更多的努力使其更加高效。值得在最新的node中尝试一下。


2
许多 Node 开发人员认为,Node 最好的部分之一实际上是它单线程的特性。线程引入了一系列共享资源的难题,而 Node 完全通过仅进行非阻塞 IO 来避免这些问题。
这并不意味着 Node 仅限于单线程。只是获取线程并发的方法与您寻找的方法不同。处理线程的标准方式是使用 Node 自带的 cluster 模块。这是比在代码中手动处理线程更简单的方法。
在处理您代码中的异步编程(例如,避免嵌套回调金字塔)时,Fibers库中的[Future]组件是一个不错的选择。我还建议您查看基于Fibers的Asyncblock。 Fibers很好,因为它们允许您通过复制堆栈,然后在单线程上跳转堆栈来隐藏回调。这样可以省去真正的线程麻烦,同时给您带来了好处。缺点是使用Fibers时堆栈跟踪可能会有些奇怪,但并不太严重。 如果您不需要担心异步问题,而更想进行大量处理而无需阻塞,则每隔一段时间简单地调用process.nextTick(callback)就足够了。

嗯,你的建议——关于集群——正是我最初考虑的。但问题在于它们的开销——每次fork一个新进程时都需要初始化一个新的v8实例(约30毫秒,10MB)。所以,你不能创建很多个。这段话直接摘自Node文档: 这些子节点(关于子进程)仍然是全新的V8实例。假设每个新节点至少需要30毫秒的启动时间和10MB的内存。也就是说,你不能创建成千上万个这样的节点。 - Parth Thakkar
1
这正是集群的理念。您可以为每个CPU核心运行一个工作进程。多余的进程很可能是不必要的。即使是CPU密集型任务,异步风格也能很好地完成。但是,如果您真的需要完整的线程,您应该考虑完全切换到另一个服务器后端。 - genericdave

1
也许更多关于你正在执行的任务的信息会有所帮助。为什么你需要创建成千上万个线程(正如你在对genericdave的回答中提到的)?在Node中完成这种事情的通常方法是启动一个工作进程(使用fork或其他方法),它始终运行并且可以通过消息进行通信。换句话说,不要每次需要执行任何任务时都启动一个新的工作进程,而只需向已经运行的工作进程发送消息,并在完成后获得响应。老实说,我认为启动成千上万个实际线程也不会很有效率,因为你仍然受到CPU的限制。
现在,在说了所有这些之后,我最近一直在使用Hook.io进行大量工作,它似乎非常适合将这种任务转移到其他进程中,也许它可以实现你的需求。

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