节点有一个完全不同的范式, 一旦正确捕捉到, 更容易看到这种不同的解决问题方式。 您在节点应用程序中从不需要多个线条(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, 回到队列的尾端, 您已经使用了您的分队列! ”