그래서 Node.js의 작동 방식을 이해했습니다. 이벤트를 수신 한 다음이를 작업자 풀에 위임하는 단일 리스너 스레드가 있습니다. 작업자 스레드는 작업이 완료되면 리스너에게 알리고 리스너는 호출자에게 응답을 반환합니다.
내 질문은 이것이다 : Node.js에서 HTTP 서버를 세우고 라우팅 된 경로 이벤트 중 하나 (예 : “/ test / sleep”)에서 sleep을 호출하면 전체 시스템이 중단됩니다. 단일 리스너 스레드조차. 그러나 내 이해는이 코드가 작업자 풀에서 발생한다는 것입니다.
대조적으로 Mongoose를 사용하여 MongoDB와 통신 할 때 DB 읽기는 값 비싼 I / O 작업입니다. Node는 작업을 스레드에 위임하고 완료되면 콜백을받을 수있는 것 같습니다. DB에서로드하는 데 걸리는 시간이 시스템을 차단하지 않는 것 같습니다.
Node.js는 스레드 풀 스레드와 리스너 스레드를 어떻게 사용하기로 결정합니까? 휴면 상태이고 스레드 풀 스레드 만 차단하는 이벤트 코드를 작성할 수없는 이유는 무엇입니까?
답변
노드의 작동 방식에 대한 이해는 정확하지 않습니다.하지만 상황의 현실은 실제로 상당히 복잡하고 일반적으로 “노드는 단일 스레드”와 같이 일을 지나치게 단순화하는 간결한 작은 문구로 요약되기 때문에 일반적인 오해입니다. .
지금은 cluster 및 webworker-threads를 통한 명시 적 다중 처리 / 다중 스레드를 무시 하고 일반적인 비 스레드 노드에 대해서만 이야기하겠습니다.
노드는 단일 이벤트 루프에서 실행됩니다. 단일 스레드이며 해당 스레드 하나만 얻을 수 있습니다. 작성한 모든 자바 스크립트는이 루프에서 실행되며, 해당 코드에서 차단 작업이 발생하면 전체 루프를 차단하고 완료 될 때까지 다른 작업은 발생하지 않습니다. 이것은 일반적으로 많이 듣게되는 노드의 단일 스레드 특성입니다. 그러나 전체 그림이 아닙니다.
일반적으로 C / C ++로 작성된 특정 함수 및 모듈은 비동기 I / O를 지원합니다. 이러한 함수와 메서드를 호출하면 내부적으로 작업자 스레드에 대한 호출 전달을 관리합니다. 예를 들어, fs
모듈을 사용하여 파일을 요청하면 fs
모듈은 해당 호출을 작업자 스레드에 전달하고 해당 작업자는 응답을 기다린 다음 응답을 기다립니다. 그런 다음 그 동안에. 이 모든 것은 노드 개발자 인 당신에게서 추상화되고 일부는 libuv 사용을 통해 모듈 개발자로부터 추상화됩니다 .
Denis Dollfus가 의견에서 지적했듯이 ( 비슷한 질문에 대한 이 답변 에서) libuv가 비동기 I / O를 달성하기 위해 사용하는 전략은 항상 스레드 풀이 아닙니다. 특히 http
모듈의 경우 다른 전략이 이때 사용됩니다. 여기서 우리의 목적을 위해 비동기 컨텍스트가 어떻게 달성되는지 (libuv를 사용하여) 그리고 libuv가 유지 관리하는 스레드 풀이 비동기 성을 달성하기 위해 해당 라이브러리에서 제공하는 여러 전략 중 하나라는 점을 주목하는 것이 주로 중요합니다.
주로 관련된 탄젠트에 대해서는 이 훌륭한 기사에서 노드가 어떻게 비동기 성을 달성하는지에 대한 훨씬 더 깊은 분석과 관련된 잠재적 인 문제와이를 처리하는 방법 이 있습니다. 대부분은 위에서 작성한 내용을 확장하지만 추가로 지적합니다.
- 네이티브 C ++ 및 libuv를 사용하는 프로젝트에 포함하는 모든 외부 모듈은 스레드 풀을 사용할 가능성이 높습니다 (예 : 데이터베이스 액세스).
- libuv의 기본 스레드 풀 크기는 4이며 대기열을 사용하여 스레드 풀에 대한 액세스를 관리합니다. 결론은 5 개의 장기 실행 DB 쿼리가 모두 동시에 진행되는 경우 그중 하나 (및 다른 비동기식 스레드 풀에 의존하는 작업)은 해당 쿼리가 시작되기 전에 완료되기를 기다립니다.
UV_THREADPOOL_SIZE
스레드 풀이 필요하고 생성되기 전에 수행하는 한 환경 변수를 통해 스레드 풀의 크기를 늘려이 문제를 완화 할 수 있습니다 .process.env.UV_THREADPOOL_SIZE = 10;
노드에서 기존의 다중 처리 또는 다중 스레딩을 원하는 경우 내장 cluster
모듈 또는 앞서 언급 한 다양한 기타 모듈을 통해 가져 webworker-threads
오거나 작업을 덩어리로 만들고 수동으로 setTimeout
또는 setImmediate
또는 process.nextTick
작업을 일시 중지하고 이후 루프에서 계속하여 다른 프로세스를 완료 할 수 있습니다 (권장되지 않음).
자바 스크립트로 장기 실행 / 차단 코드를 작성하는 경우 실수를 한 것입니다. 다른 언어는 훨씬 더 효율적으로 수행됩니다.
답변
그래서 Node.js의 작동 방식을 이해했습니다. 이벤트를 수신 한 다음이를 작업자 풀에 위임하는 단일 리스너 스레드가 있습니다. 작업자 스레드는 작업이 완료되면 리스너에게 알리고 리스너는 호출자에게 응답을 반환합니다.
이것은 실제로 정확하지 않습니다. Node.js에는 자바 스크립트 실행을 수행하는 단일 “작업자”스레드 만 있습니다. 노드 내에 IO 처리를 처리하는 스레드가 있지만이를 “작업자”로 생각하는 것은 오해입니다. 실제로 IO 처리와 노드의 내부 구현에 대한 몇 가지 기타 세부 사항이 있지만 프로그래머로서 MAX_LISTENERS와 같은 몇 가지 기타 매개 변수 외에는 동작에 영향을 줄 수 없습니다.
내 질문은 이것이다 : Node.js에서 HTTP 서버를 세우고 라우팅 된 경로 이벤트 중 하나 (예 : “/ test / sleep”)에서 sleep을 호출하면 전체 시스템이 중단됩니다. 단일 리스너 스레드조차. 그러나 내 이해는이 코드가 작업자 풀에서 발생한다는 것입니다.
JavaScript에는 수면 메커니즘이 없습니다. “수면”이 의미한다고 생각하는 코드 스 니펫을 게시하면 더 구체적으로 논의 할 수 있습니다. time.sleep(30)
예를 들어, 파이썬에서 와 같은 것을 시뮬레이션하기 위해 호출 할 함수는 없습니다 . 있다 setTimeout
그러나 그것은 근본적으로 잠을 잘 수 있습니다. setTimeout
및 setInterval
명시 적으로 해제 아니라 블록의 코드 비트들은 다른 주 실행 스레드에서 실행할 수 있도록 이벤트 루프. 당신이 할 수있는 유일한 일은 인 메모리 계산으로 CPU를 바쁘게 루프하는 것입니다. 이것은 실제로 메인 실행 스레드를 고갈시키고 프로그램을 응답하지 않게 만듭니다.
Node.js는 스레드 풀 스레드와 리스너 스레드를 어떻게 사용하기로 결정합니까? 휴면 상태이고 스레드 풀 스레드 만 차단하는 이벤트 코드를 작성할 수없는 이유는 무엇입니까?
네트워크 IO는 항상 비동기입니다. 이야기의 끝. 디스크 IO에는 동기 및 비동기 API가 모두 있으므로 “결정”이 없습니다. node.js는 sync와 일반 비동기를 호출하는 API 핵심 함수에 따라 작동합니다. 예를 들면 : fs.readFile
대 fs.readFileSync
. 하위 프로세스의 경우 별도 child_process.exec
및 child_process.execSync
API도 있습니다.
경험상 항상 비동기 API를 사용합니다. 동기화 API를 사용하는 유효한 이유는 연결을 수신하기 전에 네트워크 서비스의 초기화 코드 또는 빌드 도구 및 그런 종류의 네트워크 요청을 수락하지 않는 간단한 스크립트 때문입니다.
답변
스레드 풀 사용시기 및 사용자 :
먼저 컴퓨터에 Node를 사용 / 설치하면 컴퓨터의 노드 프로세스라고하는 다른 프로세스 중에서 프로세스를 시작하고 사용자가 죽일 때까지 계속 실행됩니다. 이 실행 프로세스는 소위 단일 스레드입니다.
따라서 단일 스레드의 메커니즘으로 인해 노드 애플리케이션을 쉽게 차단할 수 있지만 이것은 Node.js가 테이블에 제공하는 고유 한 기능 중 하나입니다. 따라서 노드 애플리케이션을 다시 실행하면 단일 스레드에서만 실행됩니다. 동시에 애플리케이션에 액세스하는 사용자가 1 백만 명이든 백만 명이든 상관 없습니다.
이제 노드 애플리케이션을 시작할 때 nodejs의 단일 스레드에서 일어나는 일을 정확히 이해합시다. 처음에 프로그램이 초기화 된 다음 모든 최상위 코드가 실행됩니다. 즉, 콜백 함수 내에없는 모든 코드가 실행됩니다 (모든 콜백 함수 내의 모든 코드가 이벤트 루프에서 실행된다는 것을 기억하십시오 ).
그 후 실행 된 모든 모듈 코드가 모든 콜백을 등록하고 마지막으로 애플리케이션에 대한 이벤트 루프가 시작됩니다.
따라서 모든 콜백 함수와 해당 함수 내의 코드가 이벤트 루프에서 실행되기 전에 논의했듯이. 이벤트 루프에서 부하는 여러 단계로 분산됩니다. 어쨌든 여기서 이벤트 루프에 대해 논의하지 않을 것입니다.
스레드 풀을 더 잘 이해하기 위해 이벤트 루프에서 하나의 콜백 함수 내부의 코드가 다른 콜백 함수 내부의 코드 실행을 완료 한 후 실행되는 것을 상상해 보라고 요청합니다. 이제 일부 작업이 실제로 너무 무겁다면. 그런 다음 nodejs 단일 스레드를 차단합니다. 그래서 이벤트 루프와 같은 스레드 풀이 libuv 라이브러리에 의해 Node.js에 제공되는 곳입니다.
따라서 스레드 풀은 nodejs 자체의 일부가 아니며 libuv에 의해 제공되어 무거운 업무를 libuv에 오프로드하고 libuv는 해당 코드를 자체 스레드에서 실행하고 실행 후 libuv는 이벤트 루프의 이벤트에 결과를 반환합니다.
스레드 풀은 기본 단일 스레드와 완전히 별 개인 4 개의 추가 스레드를 제공합니다. 그리고 실제로 최대 128 개의 스레드를 구성 할 수 있습니다.
따라서이 모든 스레드가 함께 스레드 풀을 형성했습니다. 그러면 이벤트 루프가 자동으로 무거운 작업을 스레드 풀로 오프로드 할 수 있습니다.
재미있는 부분은이 모든 것이 장면 뒤에서 자동으로 발생한다는 것입니다. 스레드 풀로 이동하는 것과 그렇지 않은 것을 결정하는 것은 우리 개발자가 아닙니다.
스레드 풀에는 다음과 같은 많은 작업이 있습니다.
-> All operations dealing with files
->Everyting is related to cryptography, like caching passwords.
->All compression stuff
->DNS lookups
답변
이 오해는 선제 적 멀티 태스킹과 협동 적 멀티 태스킹의 차이 일뿐입니다.
모든 놀이기구에 실제로 한 줄이 있기 때문에 수면은 카니발 전체를 끄고 게이트를 닫았습니다. “JS 인터프리터와 다른 것들”이라고 생각하고 스레드를 무시하십시오 … 당신에게는 스레드가 하나뿐입니다.
… 차단하지 마십시오.