Q) 자바스크립트는 싱글 스레드 언어입니다. 그러나 node.js에서 작업하면 두세 개 작업을 동시에 할 수 있는데, 원리가 뭘까요?
A) Node.js는 파일 시스템 작업, 네트워크 요청 등 대부분의 작업을 비동기로 처리합니다. 콜백(callback), 프로미스(promises), async/await 등의 기능으로 한 번에 여러 요청을 보내더라도 꼬이지 않고 순차적 처리가 되는데요, 비동기 작업을 통해서 동시에 여러 작업을 거의 동시에 처리할 수 있습니다.
T : 순차적 처리라고 하셨는데, 동시에 작업하는 것과는 약간 개념이 다른 것 같습니다. 그렇다면, 실행에 1초가 걸리는 함수를 100번 호출하면 100초의 시간이 걸리는 걸까요?
나 : 헉 그러게요...
T : 이벤트 루프에 대해 공부해보시면 좋을 것 같습니다! 아마 실제로 이렇게 100번 함수를 호출하면 1초 조금 넘는 시간밖에 걸리지 않을 거예요.
이벤트 루프(Event Loop)
Node.js의 핵심!
Node.js는 libuv 라이브러리를 기반으로 구현되어 있으며, libuv는 비동기 I/O 작업을 처리하기 위한 이벤트 루프(event loop)를 제공합니다. 이 이벤트 루프는 비동기 작업들(예: 파일 I/O, 네트워크 요청 등)을 관리하고, 작업이 완료되면 해당 작업에 연결된 콜백 함수를 실행시킵니다. 이벤트 루프는 싱글 스레드에서 실행되지만, I/O 작업은 실제로는 Node.js의 백그라운드에서 비동기적으로 처리됩니다. 이렇게 함으로써, 이벤트 루프가 일어나는 동안에 다른 작업을 동시에 계속 진행할 수 있습니다.
이벤트 루프(Event Loop)의 작동 원리
싱글 스레드
JavaScript는 싱글 스레드로 실행되므로, 한 시점에 하나의 작업만 처리할 수 있습니다. 즉, 코드가 한 줄씩 순차적으로 실행됩니다.
비동기 처리
비동기 작업은 예를 들어 데이터베이스 쿼리, 파일 읽기/쓰기, 네트워크 요청 같은 I/O 작업을 포함합니다. 이러한 작업들은 자바스크립트 엔진이 아닌 Node.js의 C++ 기반의 libuv 라이브러리에 의해 처리됩니다.
이벤트 루프와 콜백 큐
이벤트 루프는 실행할 코드가 없을 때 비동기 작업의 결과(예: 데이터베이스 쿼리 응답)를 기다립니다. 비동기 작업이 완료되면, 해당 작업에 연결된 콜백 함수가 콜백 큐에 추가됩니다.
이벤트 루프는 호출 스택(Call Stack)이 비어 있을 때, 콜백 큐에서 콜백 함수를 하나씩 꺼내 실행 스택에 넣고 실행합니다.
동시성 처리
Node.js는 이벤트 루프와 비동기 I/O 작업을 통해 '동시에' 여러 작업을 '처리하는 것처럼' 보이게 만듭니다. 실제로는 동시에 여러 코드를 실행하는 것이 아니라, I/O 작업이 백그라운드에서 처리되고, 그 결과를 적절한 순간에 빠르게 콜백 함수로 가져와 처리함으로써 비동기 작업들을 효율적으로 관리합니다.
예시
1초가 걸리는 비동기 함수를 100번 호출한다고 가정했을 때, 이 함수들은 거의 동시에 백그라운드에서 실행될 것이고, 각각의 결과는 순차적으로 이벤트 루프에 의해 처리됩니다. 따라서 전체 실행 시간은 1초 조금 넘게 걸릴 것입니다, 이는 각 작업이 병렬적으로 실행되기 때문입니다.
결론적으로, 이벤트 루프는 JavaScript의 비동기 작업을 효율적으로 관리하는 매커니즘으로, 싱글 스레드의 제약을 극복하고 효율적인 동시성을 제공합니다. 이는 Node.js가 대규모 I/O 작업을 처리하는 웹 애플리케이션에 적합한 이유 중 하나입니다.