Nodejs 는 싱글스레드 논블로킹(I/O) 이다.
기본적으로 스레드와 프로세스개념을 안다는 가정하에,
우리는 싱글스레드라면 특정 일(job)을 하고있을때에 다른일을 못한다는 것을 알고 있다.
그런데 Nodejs 는 어떻게 하나의 스레드로 I/O 가 발생했을때 비동기적으로 처리가 가능할까?
노드.js 는 이벤트 루프를 기반으로 모든 프로세스가 진행된다.
설명하기에 앞서, 각각에 페이즈별로 진행하는것으로 유도하는 함수들이 있다.
함수들과 페이즈를 매칭시켜가면서 읽으면 좋다.
Timer - Pending Callbacks - Idle, Prepare - Poll - Check- Close Callback - Timer
각 페이즈 사이에 -
부분 즉 넘어가는 곳을 Tick 이라고 한다. (process.nextTick()
)
각각에 페이즈별로 어떤일을 하는지 아래에 간략하게 설명한다.
타이머들을 다루는 함수로, setTimeout, setInterval
같은 특정시간 이후의 실행되는 것들에 대해 저장해놓고, 빼서 검증하는 페이즈이다.
저장하는곳은 Min-Heap
이다. 이진트리로 이루어져있는 데이터 저장소인데, 최대값, 최소값을 구하는데 효율적인 자료구조라고 한다.
타이머의 설정한 시간 오름차순으로 저장하기에, 위에서부터 검사하면서 false
가 나오면 바로 탐색을 중단한다.
이처럼 페이즈가 도달할때마다 체크하기에 setTimeout(func, 1000)
코드를 작성해도 정확히 1000ms 후에 실행되지 않는다. (이벤트루프, 타이머 페이즈 실행시간이 추가된다.)
실행할 수 있는 모든 작업을 하거나, 실행 한도에 다다르면 다음 페이즈인 Pending Callbacks
로 넘어간다.
실행 한도란 Node에서 한 페이즈에서 가능한 최대 수치를 말하는데, 정확한 숫자로는 표현할수없다. 왜냐하면 매우 다양한 곳에서 이벤트를 호출하고있고, 비동기적인 처리를 여러방면으로 (I/O, tick event) push
하고있기에, 작업한도는 불규칙적으로 변화한다.
단, V8 엔진의 최대 힙 사이즈를 늘린다면 실행한도를 늘릴수있다.
toobusy
라이브러리를 통해 체크할 수 있다.
pending-queue
에담기는 callback 을 관리
코드의 직접적인 실행결과에 영향을 끼치지 않는 상태이며, Node.js 의 내부적인 관리를 위한 상태이다.
Timer Phase
에서 실행하지 않는 모든함수들, I/O가 실행된다.
setImmediate
함수의 콜백에 담긴 함수를 실행한다. 이로써 process.nextTick
함수는 즉시실행 되고, setImmediate
함수는 다음 틱에 실행 되는걸 알수있다. 두개의 함수명이 바뀐게 아니냐는 말이 포럼에서 많이들 얘기한다.
socket.on('close', () => {});
과 같은 close 이벤트 타입의 핸들러를 처리하는 페이즈.
정확하게는 uv_close()를 부르면서 종료된 핸들러의 콜백들을 처리하는 페이즈다
현재 업데이트중
참고 사이트
https://www.korecmblog.com/node-js-event-loop/
: 훨씬 상세하게 잘 정리해주신 블로그. 딥하게 이해하기 좋은 글이었습니다.
https://github.com/lloyd/node-toobusy