2022-06-20 04:43:28
Node.js 的非阻塞单线程架构和事件循环是其高性能的关键特性。以下是对这些概念的详细解释,并结合提供的代码示例进行分析:
一、Node.js 非阻塞单线程架构单线程:Node.js 的主线程是单线程的,负责处理 JavaScript 代码的执行。这意味着所有的同步代码都在同一个线程中执行,避免了多线程环境下的锁和同步问题。
非阻塞 I/O:Node.js 通过事件循环和线程池实现非阻塞 I/O 操作。当遇到 I/O 操作(如文件读写、网络请求等)时,Node.js 会将这些操作交给线程池处理,主线程继续执行后续代码,不会等待 I/O 操作完成。
事件驱动:Node.js 使用事件驱动模型,通过事件循环来处理异步操作的结果。当 I/O 操作完成时,线程池会将结果通过回调函数或 Promise 返回给主线程,主线程在事件循环中处理这些结果。
事件循环是 Node.js 处理异步操作的核心机制,它分为以下几个阶段:
检索新的 I/O 事件。
执行与 I/O 相关的回调(除了 setTimeout、setInterval、setImmediate 的回调)。
如果队列为空,检查是否有 setImmediate 的回调需要执行。如果有,进入下一个阶段;如果没有,则等待新的 I/O 事件。
提供的代码示例展示了 Node.js 的事件循环和异步操作:
cpuFocus 函数:
模拟 CPU 密集型计算,通过 Array.map 进行大量随机数生成。
使用 setImmediate 将部分计算任务推迟到事件循环的检查阶段执行。
由于是同步代码,会阻塞主线程,导致 timer 的输出被延迟。
ioFocus 函数:
模拟 I/O 密集型操作,使用 await sleep(基于 setTimeout 的 Promise 化)进行异步等待。
通过 setImmediate 将后续的异步操作推迟到事件循环的检查阶段执行。
由于是异步操作,不会阻塞主线程,timer 的输出会正常进行。
timer 函数:
使用 setInterval 每秒输出一次当前秒数。
如果 second 达到 num(默认为 10),则清除定时器。
testmode = 1(I/O 测试):
ioFocus 的异步操作不会阻塞主线程,timer 的输出会正常进行。
输出顺序:timer 的秒数输出和 ioFocus 的异步日志会交替出现。
testmode = 2(CPU 测试):
cpuFocus 的同步计算会阻塞主线程,timer 的输出会被延迟。
输出顺序:先完成所有同步计算,然后输出 timer 的剩余秒数。
testmode = 3 或 4(I/O + CPU 测试):
结合了 I/O 和 CPU 操作的行为,具体输出顺序取决于两者的执行顺序和事件循环的调度。