Node.js中的I/O密集是什么意思?

10

我正在学习Node.js,并发现Node.js最适合用于I/O密集型任务,这让我有些困惑。经过一些研究,我找到了这个说法:“读取和/或写入大量数据的应用程序”。那么,这是否意味着Node.js最适合用于数据操作,即读取大量数据、提取必要数据并将其发送回客户端?

4个回答

15
一个Node.js应用程序可以很好地被设计成包含非I/O的内容,并不仅适用于大数据应用程序(事实上,大数据与其毫无关系)。
默认情况下,Node.js的简单实现在应用程序不需要进行CPU密集型操作而是大部分时间都在执行I/O(输入/输出)任务时表现最佳,例如读取/写入数据库、从文件读取/写入、读取/发送网络数据等。这与大数据无关,而是关乎服务器花费大部分时间在做什么。
出人意料的是(对某些人来说),由于web服务器的主要工作是响应通常是数据请求的http请求,因此大多数web服务器花费大部分时间都在获取、读写和发送数据,这些都是I/O任务。在Node.js设计中,所有这些I/O任务以异步的、非阻塞的方式发生,并使用事件来标识这些操作何时完成。这就是描述node.js时“事件驱动设计”这一短语的来源。这正好使得Node.js在处理主要涉及I/O的任务时非常高效。这是一个简单实现的Node.js所擅长的。它通常比纯线程化的服务器设计更好,后者将每个当前正在进行的I/O操作都分配一个操作系统线程(许多服务器框架最初采用的设计)。如果你有 CPU 密集型的任务(大量的计算、图像处理、重度加密操作等),并且这些任务经常执行或者需要很长时间,那么最好将这些任务放在一个工作线程或者另一个进程中,并在 node.js 的主进程和这个工作线程之间进行通信,以完成这些 CPU 密集型的工作。过去,node.js 没有 Worker Threads,因此处理这种任务比较麻烦,通常需要使用一个或多个额外的进程(通过集群或额外的专用进程)来处理这些 CPU 密集型的工作,但现在你可以使用 Worker Threads,这会更加方便。
例如,我有一个服务器任务需要非常复杂的加密操作(执行十亿次加密操作)。如果我把它放在主 Node.js 线程中,这实际上会阻塞事件循环,以至于当这个重度的加密操作运行时,我的服务器无法处理其他请求,这将破坏我的服务器的响应能力。
但是,我成功地将加密工作转移到了一个工作线程(实际上是几个工作线程),然后可以在这些工作线程上快速完成加密操作,而我的主线程仍然活跃,可以及时处理其他不相关的传入请求。

1
关于 Node.js 中的 CPU 密集型请求,如果我们将 CPU 重负工作移入工作线程,这是否意味着我们可以自由地使用 Node.js 处理这些繁重的任务? - SAM
1
@SAM - 是的,你可以使用node.js处理繁重的任务。你只需要将CPU密集型的操作(如果有的话)从主线程移到工作线程中。大多数常规的Web服务器并不具备CPU密集型操作,但这显然完全取决于你的服务器正在做什么。 - jfriend00
很棒,但有点奇怪的是,很多人在网络上说Node不能用于重型任务,而实际上它可以处理这样的重型任务,而且不需要学习Java、C#或其他被认为对此类重型任务有更好支持的语言。 - SAM
1
@SAM - 这可能是在node.js没有工作线程之前的历史声誉。但即使在那时,人们也可以使用子进程和工作队列来解决问题。然后,这可能只是一个被重复太多次而被很多人认为是普遍偏见的问题。在过去几年中,node.js已经成长了很多。 - jfriend00

4
首先,大数据与Node.js无关。
I/O密集意味着给定任务通常会等待I/O。最好的例子是文件操作和网络。
如果处理器必须定期等待数据到达,则该任务被视为I/O密集型。
Node.js的异步特性使其非常擅长处理I/O密集型任务,因为它可以在异步等待数据到达时继续执行其他工作。
例如,如果有10个客户端连接到服务器,其中一个客户端请求处理繁重的数据或任务,我的服务器不应该被卡住或等待此任务完成,否则将导致对其他9个客户端的响应时间更长或用户体验差。相反,服务器应该允许其他9个客户端从服务器请求数据或任务,并在各自的任务完成后向客户端发送响应。
PS:您可以学习Node.js中的事件循环。

3
Node.js擅长于作为客户端和数据源之间的中间层,即输入和输出。它采用非阻塞事件驱动方法,这也是它优秀的原因之一。例如,当您向Node.js应用程序发出请求以从数据库获取某些数据时,Node.js将请求该数据并立即返回其他请求,而不会被数据库请求阻塞。一旦数据库发送回数据,Node.js就会触发回调(或解析承诺)并继续前进。这些输入和输出事件之间没有竞争条件,因为它们的同步是在单线程机制Event Loop中完成的。只有一个事件可以被处理。我们可以将Event Loop想象成游乐园中的单座过山车,有许多人排队等待依次乘坐。您能否参加取决于您排队的时间,您的重要性或朋友是否为您保留了位置,但无论如何,每次只能有一个人参与。
这种非阻塞的事件驱动方法使Node.js能够对输入和输出事件做出高效反应,并处理许多读/写操作,因为它实际上没有进行太多处理,CPU工作量相当低。它只是作为您和数据之间的中间层。
另一方面,如果这些事件会导致某些强烈的CPU操作,Node.js的性能表现会相当差,因为事件循环一次只能处理一个事件。
用上面的过山车比喻,CPU密集型任务就像一个人正在进行非常长的乘坐,而所有其他人都必须等待他们完成。
Node.js的新版本确实获得了一些工具,允许它同时执行多个任务(并行),通过使用workers。这里的诀窍在于每个工作池都有自己的事件循环,这允许应用程序将强烈的工作移入不同的线程,并与应用程序的其余部分并行运行。请注意,只有在运行在具有多个核心的机器上时,这实际上才有帮助。如果您的机器只有一个内核,无论您使用什么工具,情况都很糟糕,因为在单个内核机器上无法真正并行执行任何操作。

嗨)) 谢谢您的友善回答,我有一个问题,我想创建一个需要大量CPU操作的项目,如果我像您说的那样自由使用Node.js并使用工作线程来处理CPU密集型工作,这样可以吗? - SAM

0

在大量 I/O 任务的情况下,绝大多数时间都花费在等待网络、文件系统和可能的数据库 I/O 完成上。提高硬盘速度或网络连接可以改善整体性能。

Node.js 在其最基本的形式中最适合这种类型的计算。Node.js 中的所有 I/O 都是非阻塞的,它允许在等待特定读取或写入完成时服务其他请求。


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