Node.js는 이제 높은 동시성 네트워크 애플리케이션 서비스 구축을 위한 도구 상자의 구성원이 되었습니다. Node.js가 대중의 사랑을 받는 이유는 무엇입니까? 이 문서에서는 프로세스, 스레드, 코루틴 및 I/O 모델의 기본 개념부터 시작하여 Node.js 및 동시성 모델에 대한 포괄적인 소개를 제공합니다.
우리는 일반적으로 프로그램의 실행 인스턴스를 프로세스라고 부릅니다. 이는 운영 체제에 의한 자원 할당 및 스케줄링을 위한 기본 단위입니다. 일반적으로 다음과 같은 부분이 포함됩니다.
进程表
的表格,每个进程占用一个进程表项
(也叫进程控制块
사용자 모드 스레드는 완전히 사용자 공간에 내장된 스레드입니다. 주요 기능은 다음과 같습니다.
Fiber라고도 불리는 Coroutine은 개발자가 일정 관리, 상태 유지 관리 및 기타 동작을 수행하기 위해 관리하는 스레드 기반 프로그램 실행 메커니즘입니다.
async/await
는 다음 예와 같이 코루틴을 구현한 것입니다. function updateUserName(id, name) { const user = getUserById(id); user.updateName(name); return true; } async function updateUserNameAsync(id, name) { const user = await getUserById(id); await user.updateName(name); return true; }
updateUserName 함수는 논리 code> 및 <code>updateUserNameAsync
내의 실행 순서는 다음과 같습니다. getUserById
함수를 호출하고 해당 반환 값을 user
변수에 할당합니다. user
의 updateName
메서드는 호출자에게 true
를 반환합니다. async/await
便是协程的一种实现,比如下面的例子:
上例中,函数 updateUserName
和 updateUserNameAsync
内的逻辑执行顺序是:
getUserById
并将其返回值赋给变量 user
;user
的 updateName
方法;true
给调用者。两者的主要区别在于其实际运行过程中的状态控制:
updateUserName
的执行过程中,按照前文所述的逻辑顺序依次执行;updateUserNameAsync
的执行过程中,同样按照前文所述的逻辑顺序依次执行,只不过在遇到 await
时,updateUserNameAsync
将会被挂起并保存挂起位置当前的程序状态,直到 await
后面的程序片段返回后,才会再次唤醒 updateUserNameAsync
并恢复挂起前的程序状态,然后继续执行下一段程序。通过上面的分析我们可以大胆猜测:协程要解决的并非是进程、线程要解决的程序并发问题,而是要解决处理异步任务时所遇到的问题(比如文件操作、网络请求等);在 async/await
之前,我们只能通过回调函数来处理异步任务,这很容易使我们陷入回调地狱
updateUserName
함수 실행 중에는 위에서 언급한 논리적 순서에 따라 순차적으로 실행됩니다. 🎜🎜함수에서 updateUserNameAsync
가 실행되는 동안 await
가 발생하는 경우 updateUserNameAsync는 일시 중단되고 일시 중단된 위치에 현재 프로그램 상태를 저장합니다. <code>await
이후 프로그램 조각이 반환되고 프로그램 상태를 복원할 때까지 updateUserNameAsync
를 다시 깨우지 않습니다. 일시 중단하기 전에 다음 프로그램을 계속 진행합니다. 🎜🎜🎜위의 분석을 통해 우리는 과감하게 추측할 수 있습니다. 코루틴이 해결해야 하는 것은 프로세스와 스레드가 해결해야 하는 프로그램 동시성 문제가 아니라 비동기 작업(예: 파일 작업, 네트워크 요청 등)을 처리할 때 직면하는 문제입니다. ); async/await
이전에는 콜백 함수를 통해서만 비동기 작업을 처리할 수 있었기 때문에 콜백 지옥
에 빠지기 쉬웠습니다. 유지관리 코드는 코루틴을 통해 비동기 코드 동기화 목적을 달성할 수 있습니다. 🎜유념해야 할 점은 코루틴의 핵심 능력은 특정 프로그램을 일시정지하고 프로그램의 일시정지 상태를 유지할 수 있으며, 향후 어느 시점에 일시정지된 위치에서 재개할 수 있다는 점입니다. 정지된 위치 이후에 다음 단계를 계속 실행합니다.
전체 I/O
작업은 다음 단계를 거쳐야 합니다. I/O
操作需要经历以下阶段:
I/O
操作请求;I/O
操作请求进行处理(分为准备阶段和实际执行阶段),并将处理结果返回给用户进(线)程。我们可将 I/O
操作大致分为阻塞 I/O
、非阻塞 I/O
、同步 I/O
、异步 I/O
四种类型,在讨论这些类型之前,我们先熟悉下以下两组概念(此处假设服务 A 调用了服务 B):
阻塞/非阻塞
:
阻塞调用
;非阻塞调用
。同步/异步
:
同步
的;回调
的方式将执行结果通知给 A,那么服务 B 就是异步
的。很多人经常将阻塞/非阻塞
与同步/异步
搞混淆,故需要特别注意:
阻塞/非阻塞
针对于服务的调用者
而言;同步/异步
针对于服务的被调用者
而言。了解了阻塞/非阻塞
与同步/异步
,我们来看具体的 I/O 模型
。
定义:用户进(线)程发起 I/O
系统调用后,用户进(线)程会被立即阻塞
,直到整个 I/O
操作处理完毕并将结果返回给用户进(线)程后,用户进(线)程才能解除阻塞
状态,继续执行后续操作。
特点:
I/O
操作的时候,用户进(线)程不能进行其它操作;I/O
请求就能阻塞进(线)程,所以为了能够及时响应 I/O
请求,需要为每个请求分配一个进(线)程,这样会造成巨大的资源占用,并且对于长连接请求来说,由于进(线)程资源长期得不到释放,如果后续有新的请求,将会产生严重的性能瓶颈。定义:
I/O
系统调用后,如果该 I/O
操作未准备就绪,该 I/O
调用将会返回一个错误,用户进(线)程也无需等待,而是通过轮询的方式来检测该 I/O
操作是否就绪;I/O
操作会阻塞用户进(线)程直到执行结果返回给用户进(线)程。特点:
I/O
操作就绪状态(一般使用 while
循环),因此该模型需占用 CPU,消耗 CPU 资源;I/O
操作就绪前,用户进(线)程不会阻塞,等到 I/O
操作就绪后,后续实际的 I/O
操作将阻塞用户进(线)程;用户进(线)程发起 I/O
系统调用后,如果该 I/O
调用会导致用户进(线)程阻塞,那么该 I/O
调用便为同步 I/O
,否则为 异步 I/O
。
判断 I/O
操作同步
或异步
的标准是用户进(线)程与 I/O
I/O
작업 요청;I/O
작업 요청(준비 단계와 실제 실행 단계로 나누어짐)을 처리하고 반환합니다. 처리 결과 사용자에게 (스레드) 프로세스를 제공합니다. I/O
작업을 차단 I/O
와 비차단 I/O
로 대략 나눌 수 있습니다. , 동기 I/O
, 비동기 I/O
이러한 유형을 논의하기 전에 먼저 다음 두 가지 개념 집합에 대해 알아봅니다(여기서는 서비스를 가정합니다). A가 서비스 B에 전화함): 🎜차단/비차단
: 🎜입니다. 차단 호출
;비차단 호출
입니다. 동기/비동기
: 🎜콜백 실행 결과가 A에 통보되고, 서비스 B는 <code>비동기
됩니다.
차단/비차단
과 동기/비동기
를 혼동하는 경우가 많으므로 특별한 주의가 필요합니다. :🎜서비스의 <code>호출자
에 대한 차단/비차단 동기/비동기
code>서비스의 수신자
용입니다. 차단/비차단
및 동기/비동기
를 이해하고 구체적인 I/O 모델
을 살펴보겠습니다. . 🎜I/O
시스템 호출을 시작한 후, 사용자가 (스레드) 스레드를 입력하면 전체 I/O
작업이 처리되고 결과가 사용자(스레드) 스레드로 반환될 때까지 즉시 차단
됩니다. 차단
상태로 유지되고 후속 작업을 계속 수행합니다. 🎜🎜특징:🎜I/O
를 실행할 때; 작업을 수행하면 사용자는 (스레드) 프로세스에서 다른 작업을 수행할 수 없습니다.I/O
요청이 들어오는 것을 차단할 수 있기 때문에 동시성이 작은 애플리케이션에만 적합합니다( 스레드) 스레드이므로 I/O
요청에 시기적절하게 응답하려면 각 요청에 대해 수신(스레드) 스레드를 할당해야 합니다. 이로 인해 막대한 리소스 사용량이 발생하게 됩니다. 긴 연결 요청 예를 들어 들어오는(스레드) 프로세스 자원을 오랫동안 해제할 수 없기 때문에 향후 새로운 요청이 있을 경우 심각한 성능 병목 현상이 발생하게 됩니다. I/O
작업이 준비되지 않은 경우 I/O
호출은 오류를 반환하고 사용자는 (스레드는 기다릴 필요가 없지만 폴링을 사용하여 I/O
작업이 준비되었는지 감지합니다.I /O
이 작업은 실행 결과가 사용자 스레드에 반환될 때까지 사용자 스레드를 차단합니다. I/O
작업 준비 상태를 지속적으로 쿼리해야 하기 때문에(일반적으로 while
사용) code> 루프), 따라서 이 모델은 CPU를 점유하고 CPU 리소스를 소비해야 합니다.I/O
작업이 준비되기 전에 사용자의(스레드) 프로세스는 완료되지 않습니다. 차단됨, I/O
작업이 준비된 후 후속 실제 I/O
작업은 사용자의 (스레드) 프로세스를 차단합니다.I/O After code> 시스템 호출을 시작했습니다. , <code>I/O
호출로 인해 사용자의 스레드(스레드)가 차단되면 I/O
호출은 동기 I/O
가 됩니다. code>, 그렇지 않으면 비동기 I/O
입니다. 🎜🎜I/O
작업이 동기
인지 비동기
인지 판단하는 기준은 사용자의 진행률(스레드)과 I/ O
작업을 위한 통신 메커니즘: 🎜동기화
사용자(스레드) 프로세스와 I/O
의 경우 상호작용은 커널 버퍼를 통해 동기화됩니다. 즉, 커널은 I/O
까지 사용자(스레드) 프로세스를 차단합니다. 작업이 완료되었습니다. 同步
情况下用户进(线)程与 I/O
的交互是通过内核缓冲区进行同步的,即内核会将 I/O
操作的执行结果同步到缓冲区,然后再将缓冲区的数据复制到用户进(线)程,这个过程会阻塞用户进(线)程,直到 I/O
操作完成;异步
情况下用户进(线)程与 I/O
的交互是直接通过内核进行同步的,即内核会直接将 I/O
操作的执行结果复制到用户进(线)程,这个过程不会阻塞用户进(线)程。Node.js 采用的是单线程、基于事件驱动的异步 I/O
模型,个人认为之所以选择该模型的原因在于:
I/O
密集型的,在保证高并发的情况下,如何合理、高效地管理多线程资源相对于单线程资源的管理更加复杂。总之,本着简单、高效的目的,Node.js 采用了单线程、基于事件驱动的异步 I/O
模型,并通过主线程的 EventLoop 和辅助的 Worker 线程来实现其模型:
需要注意的是,Node.js 并不适合执行 CPU 密集型(即需要大量计算)任务;这是因为 EventLoop 与 JavaScript 代码(非异步事件任务代码)运行在同一线程(即主线程),它们中任何一个如果运行时间过长,都可能导致主线程阻塞,如果应用程序中包含大量需要长时间执行的任务,将会降低服务器的吞吐量,甚至可能导致服务器无法响应。
Node.js 是前端开发人员现在乃至未来不得不面对的技术,然而大多数前端开发人员对 Node.js 的认知仅停留在表面,为了让大家更好地理解 Node.js 的并发模型,本文先介绍了进程、线程、协程,接着介绍了不同的 I/O
Asynchronous
사용자(스레드) 프로세스와 I/O
의 경우 상호 작용이 커널을 통해 직접 동기화됩니다. , 커널은 I/O
작업의 실행 결과를 사용자 스레드에 직접 복사합니다. 이 프로세스는 사용자 스레드를 차단하지 않습니다.
I/O
모델. 개인적으로 이 모델을 선택한 이유는 다음과 같습니다.
JavaScript는 V8에서 단일 스레드 모드로 실행되며 다중 스레드를 구현하기가 매우 어렵습니다. /li> 대부분의 네트워크 애플리케이션은 I/O
집약적입니다. 높은 동시성을 보장할 때 멀티 스레드 리소스를 합리적이고 효율적으로 관리하는 방법은 단일 스레드 리소스 관리보다 더 복잡합니다. 간단히 말하면, 단순성과 효율성을 위해 Node.js는 단일 스레드, 이벤트 중심 비동기 I/O
모델을 채택하고 메인 스레드의 해당 모델을 구현하기 위한 EventLoop 및 보조 작업자 스레드:
I/O
모델, 마지막으로 Node.js의 동시성 모델에 대한 간략한 소개입니다. 소개되었지만
Node.js 동시성 모델에는 공간이 많지 않지만 그 뿌리에서 벗어나지 않으면 결코 변하지 않을 것이라고 믿습니다. 일단 관련 기본 사항을 숙지하고 Node.js의 디자인과 구현을 깊이 이해하면 두 배의 이득을 얻게 될 것입니다. 절반의 노력으로 얻은 결과. 🎜🎜마지막으로, 이 글에 틀린 부분이 있다면 바로잡아주시길 바라겠습니다. 매일매일 행복한 코딩을 하시길 바랍니다. 🎜🎜노드 관련 지식을 더 보려면 🎜nodejs 튜토리얼🎜을 방문하세요! 🎜위 내용은 Node.js의 프로세스, 스레드, 코루틴 및 동시성 모델에 대해 이야기해 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!