English 中文(简体)
在节点J? 纤维? 网络工作者? 还是线条?
原标题:Which would be better for concurrent tasks on node.js? Fibers? Web-workers? or Threads?

不久前我碰巧碰到了节点js, 并且很喜欢它。 但很快我发现它缺乏执行CPU密集型任务的能力。 于是,我开始四处寻找答案来解决这个问题: Fibers、Webworks和Treads(Thread-a-gogogo) 。 现在,要使用哪个是混乱,其中之一肯定需要使用 — — 毕竟拥有一个服务机的目的很简单,对IO没有其他好处? 需要建议!

<强 > UPATE:

我当时在想一个办法,只是需要一些建议。现在,我想到的是:让我们有一些线条(使用线条_a_go 或网络工人 ) 。现在,当我们需要更多的线条时,我们可以创造更多。但是在创建过程中会有一些限制。(不是系统所暗示的,但可能是因为管理费造成的)现在,当我们超过限制时,我们可以划出一个新的节点,并开始为它创建线条。这样,它可以一直持续到我们达到某种限制(毕竟,程序也有很大的管理费)为止。当这一限制达到时,我们就开始排队。每当一条线线变得自由,它就会被分配到一个新的任务。这样,它就可以顺利进行。

这就是我的想法。这个想法是好的吗?我对这个过程和线索有些新颖,所以没有这方面的专业知识。请分享你的意见。

谢谢。 )

最佳回答

节点有一个完全不同的范式, 一旦正确捕捉到, 更容易看到这种不同的解决问题方式。 您在节点应用程序中从不需要多个线条(1), 因为您有不同的方式来做相同的事情。 您创建了多个进程; 但与 Apache Web 服务器 Prefork mpm 是如何做的非常不同的, 例如 Apache Web 服务器 Prefork mpm 。

现在,让我们想想我们只有一个 CPU 核心, 我们将开发一个应用程序( 以节点方式) 来做一些工作。 我们的工作是处理一个在字节by- byte 上运行内容的大文件。 我们软件的最佳方法是从文件的开头开始工作, 顺着字节- 字节到结尾 。

- 嘿,哈桑,我想你要么是新人,要么是我祖父时代的老派!

- 哦,我们只有一个CPU核心

那又怎样 创造一些线人,快一点!

- 它不会这样工作。如果我创建线条,我会让它变慢。因为我会在系统上增加大量的管理费, 用于在线条之间转换, 试图给他们一个合理的时间, 在我的过程中, 试图在这些线条之间进行沟通。 除了所有这些事实之外, 我还必须思考我如何将一个工作分成多个部分, 可以平行完成。

好吧,我看你很穷,用我的电脑,它有32个核心!

- 哇,你真棒,亲爱的朋友,非常感谢,我很感激!

然后我们回去工作。现在,我们有了32个cpu核心,这要归功于我们富有的朋友。我们必须遵守的规则刚刚改变了。现在,我们要利用我们所获得的所有财富。

要使用多个核心, 我们需要找到一种方法, 将我们的工作分割成可以平行处理的碎片。 如果不是节点, 我们将会为此使用线条; 32 条线, 每个 cpu 核心各一条。 但是, 既然我们有节点, 我们将创建 32 个节点进程 。

线索可以成为节点进程的好替代方法,也许甚至是一个更好的方法;但是,只有在特定的工作类型中,工作已经定义了,我们完全控制了如何处理。 除此之外,对于任何其他类型的问题,如果工作来自外部,而我们无法控制并且想尽快回答,那么节点的方式是无可争议的优势。

- 嘿,哈桑,你还在工作吗?

- 我将工作分成若干部分,每个进程将同时处理其中一部分。

- 为什么你不创造线索?

- 对不起,我不认为它有用。你可以拿走你的电脑,如果你想的话?

- 好吧,我很酷,我只是不明白 为什么你不使用线条?

- 感谢您的电脑。 () 我已经把作品分割成碎片, 并创建了平行操作这些部件的程序。 所有 CPU 核心都将被充分利用。 我可以用线来代替程序; 但节点有这个方法, 我的老板 Parth Thakkar 想要我使用节点 。

- 好吧,如果你需要别的电脑,请告诉我。 P:

如果我创建了33个程序,而不是32个程序,操作系统调度器将插入一条线,启动另一条线,在几个周期后暂停,再启动另一条程序...这是不必要的间接费用。我不想这样做。事实上,在一个有32个核心的系统中,我甚至不想创建32个程序,31个程序可以是“unicer 。因为这个系统不仅需要我的应用程序。给其他东西留一个小空间是好的,特别是如果我们有32个房间的话。

我认为,我们现在在充分利用处理器来完成`em>CPU密集型任务方面,我们的立场是一致的。

嗯,哈桑,很抱歉我取笑你一点。我相信我现在更了解你。但是,我还需要解释一下: 跑上百条线是什么声音?我到处读到,线比叉路更快创造和哑巴。你叉路过程而不是线,你认为这是节点的最高点。那么,节点是否适合做这种工作呢?

- 别担心,我也很冷静,每个人都这么说 所以我觉得我习惯了听

节点对这个不好?

- 节点对这个非常有益, 即使线条也可以很好。 至于线条/进程创建管理, 对于您多次重复的事物, 每一毫秒都算数。 然而, 我仅创建32个过程, 它只需要一小段时间。 它只会发生一次。 它不会改变任何变化 。

- 那么我什么时候要创造上千条线呢?

- 永远不要创建成千上万的线索。但是,在一个正在从外部开展工作的系统上,就像一个处理 HTTP 请求的网络服务器;如果你对每一项请求都使用一条线索,你会创造很多线索,其中许多线索。

- 节点是不同的,虽然?

- 是的, 正是。 这里就是节点真正闪耀的地方。 就像线索比进程轻得多一样, 函数调用比线索轻得多。 节点调用功能, 而不是创建线索。 在网络服务器的例子中, 每个收到的请求都会引起函数调用 。

- 嗯,很有趣;但是如果你没有使用多个线条,你只能同时运行一个函数。 当很多请求同时到达网络服务器时, 如何能同时运行这个功能?

- 您对函数如何运行非常正确, 一次一个, 从不同时运行两个函数。 我的意思是, 在一个单一的进程中, 代码的范围是一次运行的。 OS 调度器不会来暂停此函数, 然后转到另一个函数, 除非它会暂停进程, 以便给另一个进程时间, 而不是我们进程中的另外一条线索 。 (2)

- 那么一个过程如何一次处理两个请求?

- 只要我们的系统有足够资源(记录和档案管理、网络等),一个程序就可以处理数以万计的请求。 这些职能是如何运作的,关键差异是关键。

- 嗯,我现在应该兴奋吗?

- - 可能 : () 节点在队列上环绕一个圈。 在这个队列中, 我们的工作就是我们的工作, 即我们开始处理收到的请求的电话。 最重要的是我们如何设计要运行的函数。 我们不是开始处理一个请求, 并且让呼叫者等待我们完成任务, 而是在做一个可接受的工作量后, 我们很快结束我们的职能。 当我们到了一个点, 我们需要等待另一个组件来做一些工作, 然后给我们一个值, 而不是等待这个值, 我们只需要完成我们的工作, 剩下的工作加到队列里 。

- 听起来太复杂了?

- 不,我可能听起来很复杂, 但系统本身非常简单,非常合理。

现在我想不再引用这两个开发商之间的对话,

这样,我们正在做OS 调度器通常会做的事。 我们在某些时候暂停工作, 并让其他功能调用( 如多线环境的其他线条) 继续运行, 直到我们再次轮到我们。 这比把工作留给OS 调度器更好, 它试图给系统上每条线都留出点时间。 我们知道我们的工作比OS 调度器做得更好, 并且预期我们会在我们应该停止的时候停止。

下面是简单的例子, 我们打开一个文件并阅读它来做一些关于数据的工作。

同步方式 :

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

正如您所看到的, 我们的函数要求系统打开一个文件, 而不等待打开它。 它在文件准备后通过提供下一步步骤来结束它。 当我们返回时, 节点会运行其他函数, 并按队列调。 在运行所有函数后, 事件循环会移动到下一回合...

总之,节点的范式与多轨开发完全不同;但这并不意味着它缺少东西。 对于同步的工作(我们可以决定处理的顺序和方式 ), 它与多轨平行主义一样有效。 对于来自外部的工作,比如对服务器的要求,它只是优等。


(1) 除非您正在用 C/C++ 等其他语言建立图书馆, 否则您仍然不能为拆分任务创建线条。 对于这种工作, 您有两条线条, 其中一条将继续与节点沟通, 另一条则继续实际工作 。

(2) 事实上,每个节点进程都有多个线条,原因与我在第一个脚注中提到的相同,但这绝不像1000条线条做类似的工作。这些额外线条用于接受 IO 事件和处理进程间信息。

UPDATE (As reply to a good question in comments)

@ mark, 感谢您的建设性批评。 在节点模式中, 您不应该有要花费太长的时间才能处理的功能。 除非队列中所有其他电话都设计成一个连续运行。 在计算成本高昂的任务中, 如果我们完整地查看图片, 我们可以看到这不是一个“ 我们应使用线条或进程吗 ” 的问题, 而是一个“ 我们如何以平衡的方式将这些任务分割成子任务, 在系统上同时使用多个 CPU 核心 ” 的问题 。 如果说我们将在一个有8个核心的系统上处理400个视频文件。 如果我们想要同时处理一个文件, 那么在计算成本昂贵的任务中, 如果我们想要处理同一个文件的不同部分, 也许多读的单一进程系统会更容易建立, 甚至更有效率。 我们仍然可以为此使用节点, 运行多个进程, 并在国家共享/ 通信需要时传递信息 。 正如我之前所说, 以节点方式运行的多进程是更简单的, 而不是以线条线条的, 而不是以 < / eion > 比较一个多重的连接系统, 。 在这种任务中, 我们反复阅读的系统是没有多个输入的路径, 。

至于 setTimeout (...,0) 调用; 有时需要在一个耗时任务中休息一段时间, 允许队列中的调用有他们的处理份额 。 以不同方式分配任务可以将您从这些任务中拯救出来; 但是, 这其实不是一个黑客, 这只是事件队列的工作方式 。 另外, 使用 < code> process. nextTick 来此目的要好得多, 因为当您使用 setTimeout 时, 计算和检查所通过时间将是必要的, 而“ code> process.nextTick 仅仅是我们真正想要的 : “ 嘿 tax, 回到队列的尾端, 您已经使用了您的分队列! ”

问题回答

(2016年最新消息:网络工作者正在进入 io.js - a node.js fork node.js v7 - 见下文) 。

(更新2017年:网络工作者正在进入Node.js v7 或 v8 - 见下文)

<强>(更新2018年:网络工人 are 进入Node.js Node v10.5.0 - 见下文)。

Some clarification

在阅读了上面的答复之后,我想指出,网络工作者中没有任何东西与JavaScript的哲学相悖,特别是在同值货币方面。 (如果有的话,它甚至不会由什么工作组讨论,更不会在浏览器中执行)。

您可以将网络工作者视为轻量级的微服务, 且无同步访问。 没有共享状态 。 没有锁定问题 。 没有屏蔽 。 没有同步需要 。 就像您使用节点程序中的“ 更新服务 ” 一样, 您不担心它现在已经“ 多读 ”, 因为“ 更新服务” 与您自己的事件循环没有相同的线条 。 它只是您无法同步访问的单独服务, 这才是最重要的 。 @ info: tooltip

网络工作者的情况也是如此。 与在完全独立的背景下运行的代码进行通信只是一个 API, 无论是在不同的线条、不同的过程、不同的组群、区域、集装箱还是不同的机器中, 都完全无关紧要, 因为一个严格不同步、不阻隔的API, 并且所有数据都是通过价值传递的 。

事实上,网络工作者在概念上完全适合节点,因为许多人并不知道, 顺便说一句,

但网络工作者甚至不需要使用线条来实施。 您可以在云中使用流程、 绿色线条甚至更新服务 — — 只要使用网络工作者 API 。 以价值来呼唤 API 的信息的美丽之处在于基本实施几乎无关紧要,因为同值货币模式的细节不会暴露出来。

单目事件循环对于 I/ O 约束操作来说是完美的。 它对于 CPU 约束操作, 特别是运行时间长的操作来说效果不好。 为此我们需要生成更多进程或使用线条。 以便携式方式管理子进程和进程间通信可能非常困难, 并且往往被视为对简单任务来说是超技能的, 而使用线则意味着处理非常难以正确处理的锁和同步问题。

经常建议将长期运行的CPU-受CPU约束的作业分为较小的任务(例如io.js 是Node.js的叉子,见:my tweet I was referring to io.js pull request #1159 which now redirects to Node PR #1159 that was closed on Jul 8 and replaced with Node PR #2133 - which is still open. There is some discussion taking place under those pull requests that may provide some more up to date info on the status of Web workers in io.js/Node.js.

Update 3

Latest info - thanks to NiCk Newman for posting it in the comments: There is the workers: initial implementation commit by Petka Antonov from Sep 6, 2015 that can be downloaded and tried out in this tree. See comments by NiCk Newman for details.

Update 4

至2016年5月<强力> 2016年5月 < 强力> 2016年5月 < a href="https://github.com/nodejs/node/pull/2133" rel="noreferr">PR#2133 - 工人:初步实施 已有3个月的历史。 5月30日,Matheus Moreira请我在下文的评论中对此答复作出更新,他PR 2133 关于GitHub的评论。

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

Update 6

我高兴地宣布,几天前,在2018年6月<强人>、2018年6月<强人>、<强人>网络工作者出现在Node v10.5.0中,作为实验性特征,在-实验性工人 旗帜下启动。

更多信息,请参见:

最后,我可以做第7次更新 我3岁的Stack overflow 答案,我争辩说 螺丝拉网络工人 不反对节点哲学, 只有这一次说 我们终于得到了它!

我来自我们用多行制来快速制造软件的旧思想学派。 在过去的三年里,我一直在使用Node.js, 并且是它的大支持者。正如As hasanyasin详细解释了节点如何运作以及松散功能的概念。但让我在此补充几件事。

在旧时代,我们用单一核心和低时钟速度尝试了多种方法使软件快速和平行运行。在 DOS 日中,我们使用多种方法来一次运行一个程序。在窗口中,我们开始一起运行多个应用程序(程序)。先发制人和非先发制人(或合作)的概念是测试的。我们现在知道先发制人是单核心计算机更好的多处理任务的答案。随之而来的是流程/任务和上下文转换的概念。比线概念更能进一步减少流程背景转换的负担。线索是作为轻重量替代产出新流程的标记。

因此,无论是否发出信号线 或者不是多核心或者单一核心 你的程序会被操作系统先发制人 并被时间截断

Nodejs is a single process and provides async mechanism. Here jobs are dispatched to under lying OS to perform tasks while we waiting in an event loop for the task to finish. Once we get a green signal from OS we perform what ever we need to do. Now in a way this is cooperative/non-preemptive multi-tasking, so we should never block the event loop for a very long period of time other wise we will degrade our application very fast.
So if there is ever a task that is blocking in nature or is very time consuming we will have to branch it out to the preemptive world of OS and threads. there are good examples of this is in the libuv documentation. Also if you read the documentation further you find that FileI/O is handled in threads in node.js.

所以首先,这是我们软件设计的全部内容。第二,不管他们告诉你什么,背景切换总是在发生。线索存在,而且仍然存在是有原因的,原因是它们更快地在两个过程之间转换。

头罩下有所有 c++ 和线条。 结点提供 c++ 扩展功能的方法, 并通过使用线条来进一步加快速度, 即屏蔽从源代码书写到源代码等任务, 大型数据分析等等 。

我知道有万有的答案是被接受的答案,但对于我来说,线线将存在,无论你说什么或如何隐藏在脚本后面,第二,没有人会仅仅为了速度而把东西折成线线,而只是为阻断任务而做的。而线线在Node.js 的后骨中,因此,在完全击碎多线朗之前,线线线是正确的。同样,线线与进程不同,每个核心节点进程的限制并不完全适用于线索的数量,线线线就像一个进程的子任务。事实上,线线胜了;在您的窗口任务管理器或 Linux 顶部命令中出现。它们再次变小,然后是进程。

我不确定网络工作者是否与本案相关,他们是客户端技术(在浏览器中运行),而在服务器上运行 node.js。据我所知,Fibers也在屏蔽,也就是说,他们是自愿的多重任务,所以你可以使用这些任务,但应该通过yield 来管理上下文的切换。线索实际上可能是你需要的,但是我不知道它们是否成熟。js。

worker_threads 已经实施,并被装在国旗后发运到

在许多节点开发者意见中,节点的最佳部分之一实际上是其单行性质。 线索引入了共享资源方面的一连串困难,而节点完全避免了这些困难,它只能通过不阻隔 IO 来做任何事情。

这并不是说节点 < em> 受限制 < / em> 是一个线索。 它只是说, 获取螺旋共通货币的方法与您想要的有所不同。 处理线索的标准方式是 < a href=" http://nodejs. org/ api/ croup. html" rel="nofollow" 组合 模块, 该模块与 Node 本身具有标准性。 它比在您的代码中手动处理它们简单得多。

对于在您的代码中处理无序的编程( 如在中, 避免嵌入回调金字塔), < a href=" https://github.com/laverdet/ node- fibers" rel= "nofollow" >Fibers 库中的[ freet=" a huref=" "https://github.com/scriby/asyncblock" rel=" nofollow" > > Asyncblock , 以 Fibers为基础。 Fibers是不错的, 因为它们允许您通过复制堆叠来隐藏调用, 然后按需要在单行之间跳过堆。 省下真实线索的杂物, 同时给您带来好处。 底端是, 堆叠痕迹在使用 Fibers 时会变得有点怪异, 但是它们并不坏 。

如果您不需要担心杂交的东西, 并且更有兴趣在不阻塞的情况下做大量处理, 简单的处理电话。 每隔一段时间就打回电话。 只需要一次 。 @ extTick( recall) 。

有关您正在执行的任务的更多信息会有所帮助 。 您需要创建成千上万的任务吗? 通常在节点这样做的方式是启动一个工人进程( 使用叉子或其他方法), 该过程总是运行, 并且可以传递到信息 。 换句话说, 您在每次需要执行任何任务时不要启动新工人, 只需向已经运行的工人发送信息, 并在完成后得到回应 。 说实话, 我看不出启动“ 成千上万 ” 的实际线条会非常有效 。 您仍然受到 CUPs 的限制 。

现在,在说完所有这一切之后,我一直在与Hook.io 一起做很多工作,最近看来对于将这类任务卸到其他进程来说非常有效,也许它可以完成你需要的东西。





相关问题
Silverlight, Updating the UI during processing

I have a simple silverlight multifile upload application, and i want to provide the user with some feedback, right now its only in a test phase and i dont have the webservice. Somehow i cant get the ...

Is reading from an XmlDocument object thread safe?

I was wondering if i could safely read from an XmlDocument object using SelectNodes() and SelectSingleNode() from multiple threads with no problems. MSDN says that they are not guaranteed to be ...

Terminating a thread gracefully not using TerminateThread()

My application creates a thread and that runs in the background all the time. I can only terminate the thread manually, not from within the thread callback function. At the moment I am using ...