Node.js는 이제 높은 동시성 네트워크 애플리케이션 서비스를 구축하기 위한 도구 상자의 구성원이 되었습니다. Node.js가 대중의 사랑을 받는 이유는 무엇일까요? 이 문서에서는 프로세스, 스레드, 코루틴 및 I/O 모델의 기본 개념부터 시작하여 Node.js 및 동시성 모델에 대한 포괄적인 소개를 제공합니다.
우리는 일반적으로 프로그램의 실행 인스턴스를 프로세스라고 부릅니다. 이는 운영 체제에 의한 자원 할당 및 스케줄링의 기본 단위입니다. 일반적으로 다음과 같은 부분을 포함합니다.
进程表项
进程表
(进程控制块
이라고도 함)을 차지합니다. 이 항목에는 프로그램 카운터, 스택 포인터, 메모리 할당, 열린 파일 상태 및 예약 정보와 같은 중요한 프로세스 상태가 포함됩니다. . 프로세스가 일시 중지된 후 운영 체제가 프로세스를 올바르게 다시 시작할 수 있는지 확인하는 정보입니다.프로세스는 다음과 같은 특징을 가지고 있습니다:
프로그램이 두 번 실행되는 경우 운영 체제에서 코드를 공유할 수 있도록 허용하더라도(즉, 코드의 복사본 하나만 메모리에 있음) 실행 중인 프로그램의 두 인스턴스가 서로 다르다는 것을 변경할 수 없습니다. 사실을 처리합니다.
프로세스가 실행되는 동안 중단 및 CPU 스케줄링과 같은 다양한 이유로 인해 프로세스는 다음 상태 사이에서 전환됩니다.
위의 프로세스 상태 전환 다이어그램에서 프로세스는 실행 상태에서 준비 상태 및 차단 상태로 전환할 수 있지만 준비 상태만 실행 상태로 직접 전환할 수 있음을 알 수 있습니다. 그 이유는 다음과 같습니다.
때때로 다음과 같은 문제를 해결하기 위해 스레드를 사용해야 합니다.
스레드에 관해 우리는 다음 사항을 알아야 합니다:
이제 스레드의 기본 특성을 이해했으므로 몇 가지 일반적인 스레드 유형에 대해 이야기해 보겠습니다.
커널 상태 스레드는 운영 체제에서 직접 지원하는 스레드입니다. 주요 기능은 다음과 같습니다.
사용자 모드 스레드는 사용자 공간에 완전히 구축된 스레드입니다. 주요 특징은 다음과 같습니다.
경량 프로세스(LWP)는 커널을 기반으로 구축되고 커널에서 지원되는 사용자 스레드입니다. 주요 기능은 다음과 같습니다.
사용자 공간은 경량 프로세스(LWP)를 통해서만 커널 스레드를 사용할 수 있다고 간주할 수 있습니다. 따라서 커널 스레드를 지원해야만 경량 프로세스(LWP)가 있을 수 있습니다.
대부분의 LWP(경량 프로세스) 작업에는 시스템 호출인 사용자 모드 공간이 필요합니다. 상대적으로 비용이 많이 듭니다(사용자 모드와 커널 모드 간 전환 필요).
각 경량 프로세스(LWP)는 특정 커널 스레드와 연결되어야 합니다. 따라서
모든 공유 주소 공간과 시스템 리소스에 액세스할 수 있습니다.
위에서는 일반적인 스레드 유형(커널 상태 스레드, 사용자 상태 스레드, 경량 프로세스)에 대해 간략하게 소개했습니다. 각각은 고유한 적용 범위를 가지고 있으며 필요에 따라 자유롭게 사용할 수 있습니다. 일반적인 일대일, 다대다 및 기타 모델과 같은 조합. 공간 제한으로 인해 이 기사에서는 이에 대해 너무 많이 소개하지 않습니다. 관심 있는 학생들은 스스로 공부할 수 있습니다.
Fiber라고도 불리는은 개발자가 실행 예약, 상태 유지 관리 및 기타 동작을 스스로 관리할 수 있도록 하는 스레드 기반 프로그램 실행 메커니즘입니다. 주요 기능은 다음과 같습니다
JavaScript에서 우리가 자주 사용하는 async/await
다음 예와 같이 코루틴을 구현한 것입니다.
function updateUserName(id, name) { const 사용자 = getUserById(id); user.updateName(이름); 사실을 반환; } 비동기 함수 updateUserNameAsync(id, name) { const 사용자 = getUserById(id)를 기다립니다; user.updateName(이름)을 기다립니다; 사실을 반환; }
위의 예에서 updateUserName
및 updateUserNameAsync
함수 내의 논리적 실행 순서는 다음과 같습니다.
getUserById
함수를 호출하고 해당 반환 값을 user
변수에 할당합니다.user
의 updateName
메서드를 호출하여true
합니다.둘 사이의 주요 차이점은 실제 작업 중 상태 제어에 있습니다.
updateUserNameAsync
함수가 실행되는 동안updateUserName
언급한 논리적 순서에 따라 순차적으로 실행됩니다.await
발생하면 updateUserNameAsync
일시 중단되고 현재 프로그램 상태가 일시 중단된 위치에 저장됩니다. await
이후의 프로그램 조각이 반환되고 일시 중단 전 프로그램 상태를 복원할 때까지 updateUserNameAsync
다시 활성화되지 않습니다. 그리고 다음 프로그램을 계속 진행하세요.위의 분석에서 우리는 다음과 같이 과감하게 추측할 수 있습니다. 코루틴이 해결해야 하는 것은 프로세스와 스레드가 해결해야 하는 프로그램 동시성 문제가 아니라 비동기 작업(예: 파일 작업, 네트워크 요청 등)을 처리할 때 직면하는 문제입니다. async/await
이전에는 콜백 함수를 통해서만 비동기 작업을 처리할 수 있었기 때문에 쉽게回调地狱
에 빠질 수 있었고 일반적으로 유지 관리하기 어려운 코드가 엉망이 되었습니다. 비동기 코드의 동기화를 달성할 수 있었습니다. .
명심해야 할 점은 코루틴의 핵심 기능은 특정 프로그램을 일시 중지하고 프로그램의 일시 중지 위치 상태를 유지할 수 있으며, 향후 어느 시점에 일시 중지된 위치에서 다시 시작하고 계속해서 수행할 수 있다는 것입니다. 정지 위치 이후에 다음 세그먼트를 실행합니다.
완전한 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
루프 사용) 모델은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
작업의 실행 결과를 사용자 스레드(스레드)에 직접 복사합니다. 사용자(스레드) 프로세스를 차단하지 않습니다.Node.js는 단일 스레드, 이벤트 중심 비동기 I/O
모델을 사용합니다. 개인적으로 이 모델을 선택한 이유는
I/O
집약적입니다. 높은 동시성을 보장하면서 다중 스레드 리소스를 합리적이고 효율적으로 관리하는 방법은 단일 스레드 리소스를 관리하는 것보다 더 복잡합니다.즉, 단순성과 효율성을 위해 Node.js는 단일 스레드, 이벤트 중심 비동기 I/O
모델을 채택하고 기본 스레드와 보조 Worker 스레드의 EventLoop를 통해 모델을 구현합니다
Node.js는 CPU 집약적인(즉, 많은 계산이 필요한) 작업을 수행하는 데 적합하지 않다는 점에 유의해야 합니다. 이는 EventLoop와 JavaScript 코드(비동기 이벤트 작업 코드)가 동일한 스레드에서 실행되기 때문입니다(즉, 메인 스레드) 및 그 중 하나 하나가 너무 오랫동안 실행되면 메인 스레드가 차단될 수 있습니다. 애플리케이션에 긴 실행이 필요한 작업이 많이 포함되어 있으면 서버의 처리량이 감소할 수도 있습니다. 서버가 응답하지 않게 됩니다.
Node.js는 프론트엔드 개발자가 현재는 물론 앞으로도 직면해야 할 기술입니다. 그러나 대부분의 프론트엔드 개발자는 모든 사람이 Node의 동시성 모델을 더 잘 이해할 수 있도록 Node.js에 대한 피상적인 지식만 가지고 있습니다. .js, 이 기사에서는 먼저 프로세스, 스레드 및 코루틴을 소개한 다음 다양한 I/O
모델을 소개하고 마지막으로 Node.js의 동시성 모델을 간략하게 소개합니다. Node.js 동시성 모델을 소개할 지면이 많지는 않지만, 저자는 관련 기본 원칙을 숙지하고 Node.js의 설계와 구현을 깊이 이해하면 두 배의 결과를 얻을 수 있다고 믿습니다. 절반의 노력으로.
마지막으로, 이 글에 틀린 부분이 있다면 바로잡아주시길 바랍니다. 모두들 행복한 코딩생활 되시길 바랍니다.