노드는 완전히 다른 패러다임을 가지고 있으며 올바르게 캡처되면 문제를 해결하는이 다른 방법을 더 쉽게 볼 수 있습니다. 동일한 작업을 수행하는 방법이 다르기 때문에 Node 응용 프로그램 (1)에 여러 스레드가 필요하지 않습니다. 여러 프로세스를 생성합니다. 그러나 예를 들어 Apache Web Server의 Prefork mpm이 수행하는 방식과는 매우 다릅니다.
지금은 CPU 코어가 하나 뿐이고 일부 작업을 수행하는 애플리케이션을 (노드 방식으로) 개발할 것이라고 가정 해 보겠습니다. 우리의 임무는 내용을 바이트 단위로 실행하는 큰 파일을 처리하는 것입니다. 우리 소프트웨어를위한 가장 좋은 방법은 파일의 처음부터 작업을 시작하여 바이트 단위로 끝까지 따르는 것입니다.
-헤이, 하산, 당신은 할아버지 시대의 초보이거나 아주 오래된 학교라고 생각합니다 !!! 스레드를 생성하여 훨씬 빠르게 만드는 것은 어떻습니까?
-아, CPU 코어가 하나뿐입니다.
-그래서 뭐? 스레드를 만들면 더 빨라집니다!
-그렇게 작동하지 않습니다. 스레드를 만들면 속도가 느려집니다. 스레드 간 전환을 위해 시스템에 많은 오버 헤드를 추가하고, 시간을주고, 프로세스 내부에서 이러한 스레드간에 통신을 시도하기 때문입니다. 이 모든 사실 외에도 단일 작업을 병렬로 수행 할 수있는 여러 조각으로 나누는 방법도 생각해야합니다.
-좋아요, 당신이 가난 하군요. 내 컴퓨터를 사용합시다, 그것은 32 개의 코어를 가지고 있습니다!
-와, 당신은 정말 대단해요, 친애하는 친구, 대단히 감사합니다. 감사합니다!
그런 다음 다시 일합니다. 이제 우리는 부자 친구 덕분에 32 개의 CPU 코어를 갖게되었습니다. 우리가 지켜야 할 규칙이 방금 변경되었습니다. 이제 우리는 우리에게 주어진이 모든 부를 활용하고 싶습니다.
다중 코어를 사용하려면 작업을 병렬로 처리 할 수있는 조각으로 나누는 방법을 찾아야합니다. 노드가 아니라면이를 위해 스레드를 사용합니다. CPU 코어 당 하나씩 32 개의 스레드. 그러나 Node가 있으므로 32 개의 Node 프로세스를 생성합니다.
스레드는 노드 프로세스에 대한 좋은 대안이 될 수 있습니다. 그러나 작업이 이미 정의 된 특정 종류의 작업에서만 처리 방법을 완전히 제어 할 수 있습니다. 그 외에는 우리가 통제 할 수없는 방식으로 외부에서 오는 모든 문제에 대해 가능한 한 빨리 대답하고 싶은 Node의 방식은 틀림없이 우수합니다.
-헤이, Hasan, 아직도 싱글 스레드로 작업하고 있습니까? 넌 왜 그래? 나는 당신이 원하는 것을 제공했습니다. 더 이상 변명의 여지가 없습니다. 스레드를 만들고 더 빠르게 실행하십시오.
-작업을 여러 조각으로 나누었고 모든 프로세스가이 조각 중 하나에서 병렬로 작업 할 것입니다.
-스레드를 생성하지 않는 이유는 무엇입니까?
-죄송합니다. 사용할 수없는 것 같습니다. 원하는 경우 컴퓨터를 가져갈 수 있습니까?
-아니 괜찮아, 멋지다, 왜 쓰레드를 사용하지 않는지 이해가 안 돼?
-컴퓨터 주셔서 감사합니다. :) 저는 이미 작업을 여러 조각으로 나누고이 조각들을 병렬로 작업하는 프로세스를 만듭니다. 모든 CPU 코어가 완전히 활용됩니다. 프로세스 대신 스레드로이 작업을 수행 할 수 있습니다. 하지만 Node는 이런 방식을 가지고 있고 제 상사 Parth Thakkar가 Node.js를 사용하기를 원합니다.
-좋아요, 다른 컴퓨터가 필요한지 알려주세요. :피
32 개 대신 33 개의 프로세스를 생성하면 운영 체제의 스케줄러가 스레드를 일시 중지하고, 다른 하나를 시작하고, 일부주기 후에 일시 중지하고, 다른 하나를 다시 시작합니다. 이것은 불필요한 오버 헤드입니다. 나는 그것을 원하지 않는다. 사실, 32 개의 코어가있는 시스템에서는 정확히 32 개의 프로세스를 만들고 싶지도 않을 것 입니다. 31 개는 더 좋을 수 있습니다 . 이 시스템에서 작동하는 것은 내 응용 프로그램 뿐만이 아니기 때문입니다. 다른 일을 위해 약간의 공간을 남겨 두는 것이 좋을 수 있습니다. 특히 방이 32 개인 경우 더욱 그렇습니다.
나는 우리가 CPU 집약적 인 작업을 위해 프로세서를 완전히 활용하는 것에 대해 같은 페이지에 있다고 믿습니다 .
-흠, 하산, 조금 조롱해서 미안 해요. 이제 당신을 더 잘 이해한다고 믿습니다. 하지만 여전히 설명이 필요한 것이 있습니다. 수백 개의 스레드를 실행하는 것에 대한 소문이 무엇입니까? 나는 스레드가 프로세스를 포크하는 것보다 생성하고 멍청하다는 것을 어디서나 읽었습니까? 스레드 대신 프로세스를 포크하고 Node.js에서 얻을 수있는 최고 수준이라고 생각합니다. 그렇다면 Node는 이런 종류의 작업에 적합하지 않습니까?
-걱정마, 나도 멋지다. 다들 이런 말을하니 익숙한 것 같아요.
-그래서? 노드가 이것에 좋지 않습니까?
-스레드도 좋을 수 있지만 노드는이를 위해 완벽하게 좋습니다. 스레드 / 프로세스 생성 오버 헤드에 관해서는; 당신이 많이 반복하는 것에 대해서는 밀리 초마다 중요합니다. 그러나 저는 32 개의 프로세스 만 생성하고 시간이 조금 걸립니다. 한 번만 발생합니다. 그것은 어떤 차이도 만들지 않을 것입니다.
-언제 수천 개의 스레드를 생성하고 싶습니까?
-수천 개의 스레드를 만들고 싶지 않습니다. 그러나 HTTP 요청을 처리하는 웹 서버와 같이 외부에서 작업을 수행하는 시스템에서는; 각 요청에 대해 스레드를 사용하는 경우 많은 스레드를 생성하게됩니다.
-노드는 다르지만? 권리?
-네, 맞습니다. 이것은 Node가 실제로 빛나는 곳입니다. 스레드가 프로세스보다 훨씬 가벼운 것처럼 함수 호출은 스레드보다 훨씬 가볍습니다. 노드는 스레드를 생성하는 대신 함수를 호출합니다. 웹 서버의 예에서 들어오는 모든 요청은 함수 호출을 발생시킵니다.
-흠, 흥미 롭군요. 그러나 여러 스레드를 사용하지 않는 경우 동시에 하나의 함수 만 실행할 수 있습니다. 많은 요청이 동시에 웹 서버에 도착할 때 어떻게 작동 할 수 있습니까?
-한 번에 하나씩 함수가 실행되는 방식에 대해 완벽하게 맞습니다. 단일 프로세스에서는 한 번에 하나의 코드 범위 만 실행됩니다. OS Scheduler는 프로세스의 다른 스레드가 아닌 다른 프로세스에 시간을 제공하기 위해 프로세스를 일시 중지하지 않는 한이 기능을 일시 중지하고 다른 것으로 전환하지 않습니다. (2)
-그러면 프로세스가 한 번에 2 개의 요청을 어떻게 처리 할 수 있습니까?
-시스템에 충분한 리소스 (RAM, 네트워크 등)가있는 한 프로세스는 한 번에 수만 개의 요청을 처리 할 수 있습니다. 이러한 기능이 실행되는 방식은 주요 차이점입니다.
-흠, 지금 흥분해야하나요?
-어쩌면 :) 노드는 대기열을 통해 루프를 실행합니다. 이 대기열에는 작업, 즉 들어오는 요청을 처리하기 시작한 호출이 있습니다. 여기서 가장 중요한 점은 실행할 함수를 설계하는 방식입니다. 요청을 처리하기 시작하고 호출자가 작업을 마칠 때까지 기다리게하는 대신 허용 가능한 양의 작업을 수행 한 후 신속하게 기능을 종료합니다. 다른 구성 요소가 일부 작업을 수행하고 값을 반환 할 때까지 기다려야하는 시점에 도달하면 기다리지 않고 나머지 작업을 대기열에 추가하기 만하면됩니다.
-너무 복잡하게 들리나요?
-아니요, 복잡하게 들릴 수도 있습니다. 하지만 시스템 자체는 매우 간단하고 완벽합니다.
이제이 두 개발자 간의 대화를 인용하는 것을 중단하고 이러한 기능이 작동하는 방식에 대한 마지막 간단한 예제를 마치고 답을 마무리하겠습니다.
이런 식으로 OS 스케줄러가 일반적으로 수행하는 작업을 수행합니다. 우리는 어떤 시점에서 작업을 일시 중지하고 다시 차례를 얻을 때까지 다른 함수 호출 (다중 스레드 환경의 다른 스레드와 같은)을 실행하도록합니다. 이것은 시스템의 모든 스레드에 시간을 부여하려는 OS 스케줄러에 작업을 맡기는 것보다 훨씬 낫습니다. 우리는 OS 스케줄러보다 훨씬 더 잘하고있는 것을 알고 있으며 중지해야 할 때 중지 할 것으로 예상됩니다.
다음은 파일을 열고 데이터에 대한 작업을 수행하는 간단한 예입니다.
동기 방식 :
Open File
Repeat This:
Read Some
Do the work
비동기 방식 :
Open File and Do this when it is ready: // Our function returns
Repeat this:
Read Some and when it is ready: // Returns again
Do some work
보시다시피, 우리의 함수는 시스템에 파일을 열도록 요청하고 파일이 열릴 때까지 기다리지 않습니다. 파일이 준비된 후 다음 단계를 제공하여 자동으로 완료됩니다. 돌아 오면 Node는 큐에서 다른 함수 호출을 실행합니다. 모든 기능을 실행 한 후 이벤트 루프는 다음 턴으로 이동합니다.
요약하면 Node는 멀티 스레드 개발과는 완전히 다른 패러다임을 가지고 있습니다. 그러나 이것은 그것이 부족하다는 것을 의미하지 않습니다. 동기식 작업 (처리 순서와 방법을 결정할 수 있음)의 경우 다중 스레드 병렬 처리와 마찬가지로 작동합니다. 서버에 대한 요청과 같이 외부에서 오는 작업의 경우 단순히 우수합니다.
(1) C / C ++와 같은 다른 언어로 라이브러리를 빌드하지 않는 한 작업을 분할하기위한 스레드를 생성하지 않습니다. 이러한 종류의 작업을 위해 두 개의 스레드가 있으며 그중 하나는 Node와 계속 통신하고 다른 하나는 실제 작업을 수행합니다.
(2) 사실, 모든 노드 프로세스에는 첫 번째 각주에서 언급 한 것과 같은 이유로 여러 스레드가 있습니다. 그러나 이것은 유사한 작업을 수행하는 1000 개의 스레드와는 다릅니다. 이러한 추가 스레드는 IO 이벤트를 수락하고 프로세스 간 메시징을 처리하기위한 것입니다.
업데이트 (댓글에 좋은 질문에 대한 답변으로)
@Mark, 건설적인 비판에 감사드립니다. Node의 패러다임에서는 대기열의 다른 모든 호출이 차례로 실행되도록 설계되지 않는 한 처리하는 데 너무 오래 걸리는 함수가 있어서는 안됩니다. 계산 비용이 많이 드는 작업의 경우 전체 그림을 보면 "스레드 또는 프로세스를 사용해야합니까?"라는 질문이 아님을 알 수 있습니다. 그러나 "어떻게 이러한 작업을 균형 잡힌 방식으로 하위 작업으로 분할하여 시스템에 여러 CPU 코어를 사용하여 병렬로 실행할 수 있습니까?" 코어가 8 개인 시스템에서 400 개의 비디오 파일을 처리한다고 가정 해 보겠습니다. 한 번에 하나의 파일을 처리하려면 동일한 파일의 다른 부분을 처리하는 시스템이 필요합니다.이 경우 다중 스레드 단일 프로세스 시스템이 더 쉽게 빌드되고 훨씬 더 효율적일 수 있습니다. 상태 공유 / 통신이 필요할 때 여러 프로세스를 실행하고 메시지를 전달하여이를 위해 Node를 계속 사용할 수 있습니다. 앞서 말했듯이 Node의 다중 프로세스 접근 방식은뿐만 아니라 이러한 종류의 작업에서 다중 스레드 접근 방식; 하지만 그 이상은 아닙니다. 다시 말하지만, Node가 빛나는 상황은 여러 소스에서 시스템에 대한 입력으로 이러한 작업이 들어오는 경우입니다. 여러 연결을 동시에 유지하는 것이 연결 당 스레드 또는 연결 당 프로세스에 비해 노드에서 훨씬 가볍기 때문입니다. 체계.
setTimeout(...,0)
전화에 관해서는 때로는 시간이 많이 걸리는 작업 중에 휴식을 취하여 대기열의 통화가 처리 점유율을 가질 수 있도록해야 할 수 있습니다. 작업을 여러 방법으로 나누면 이러한 작업에서 벗어날 수 있습니다. 그러나 여전히 이것은 실제로 해킹이 아니며 이벤트 대기열이 작동하는 방식입니다. 또한 process.nextTick
이 목적 을 위해 사용 하는 것이 훨씬 낫습니다.를 사용할 setTimeout
때 경과 된 시간을 계산하고 확인하는 것이 필요하지만 process.nextTick
우리가 진정 원하는 것은 "이봐, 대기열의 끝으로 돌아가십시오. 공유를 사용하셨습니다! "