我最近开始阅读很多关于 Node JS 的文章,从差异化的角度来看,我无法清楚地理解的一件事是异步与同步调用处理 I/O 的真正区别是什么。
据我了解,在多线程同步环境中,如果启动I/O,正在运行的线程将被抢占并移回等待状态。所以本质上这与 NodeJS 异步 I/O 调用发生的情况相同。在 Node JS 中,当调用 I/O 时,I/O 操作将移出当前正在运行的线程,并发送到事件解复用器进行完成和通知。I/O 完成后,回调方法将推送到事件队列进行进一步处理。
所以,我看到的唯一区别是,在 Node JS 中,我们正在节省内存(由于每个线程拥有多个调用堆栈)和 CPU(由于没有上下文切换而保存)。如果我只考虑我有足够的内存来购买,仅由于上下文切换而节省的CPU是否会产生巨大的性能差异?
如果我的上述理解不正确,那么 Java 线程与节点 JS w.r.t 之间的 I/O 处理与保持 CPU 繁忙而不浪费 CPU 周期有什么不同。我们是使用 Node JS 仅节省上下文切换 CPU 周期,还是还有更多?
根据回复,我想添加另一个场景:
请求A,请求 B 同时来到 J2ee 服务器。在此多线程环境中,每个请求需要 10 毫秒才能完成。在 10 毫秒中,5 毫秒用于执行代码逻辑以计算某些逻辑,5 毫秒用于从 DBMS 中提取大型数据集的 I/O。对 DBMS 的调用是代码的最后一行,之后应将响应发送到客户端。
如果将同一应用程序转换为节点JS应用程序,则可能会发生这种情况
请求 A 来了,5 毫秒用于处理请求。
DBMS 调用是从代码命中,但它是非阻塞的。所以一个回调方法被推送到事件队列。
- 5 毫秒后,请求 B 将再次送达请求 B 被推送到事件队列以完成 I/O。请求 B处理需要 5 毫秒。
- 事件循环运行,拾取回调请求 A 的处理程序,然后将响应发送到客户端。所以响应在 10 毫秒后发送,因为请求 A 和请求 B 都花了 5毫秒,用于同步代码块处理。
现在在这种情况下节省的时间在哪里?除了上下文切换和创建 2 个线程。无论如何,Req A 和 Req B 在 Node JS 上都需要 10 毫秒。?
据我了解,在多线程同步环境中,如果I/O 启动,正在运行的线程被抢占并移回 等待状态。所以本质上这与 NodeJS 发生的情况相同 异步 I/O 调用。
不,在 NodeJS 中,异步 I/O 调用是非阻塞 I/O。这意味着一旦线程进行了 I/O 调用,它就不会等待 I/O 完成并继续执行下一个语句/任务。
一旦 I/O 完成,它就会从事件循环队列中选取下一个任务,并最终执行在进行 I/O 调用时提供给它的回调处理程序。
如果我只是认为我有足够的内存来购买,是否保存 仅由于上下文切换,CPU就使巨大的性能 差异?
除此之外,储蓄也来自这两件事
- 无需等待 I/O 完成
- 由于线程是有限的,因此系统的容量不受它可以创建多少线程的限制。
除了上下文切换和创建 2 个线程。Req A & Req B 无论如何,两者都需要 10 毫秒的 Node JS。?
您在这里打折了一件事 - 线程在特定间隔后一个接一个地收到两个请求。因此,如果一个线程需要 10 秒,那么它将需要一个新线程来执行第二个请求。将其扩展到数千个请求,并且您的操作系统必须创建数千个线程来处理如此多的并发用户。请参考这个类比。