
Node.js는 단일 스레드로 동작하지만 이벤트 루프를 이용한 논블로킹 I/O를 지원하고, 코드 작성 시에는 Promise 객체를 활용한 비동기 처리를 async / await를 사용해 간단하게 처리할 수 있습니다. 이런 간단한 처리로 런타임이 많은 부분을 알아서 효율적으로 처리해주기 때문에 저는 지금까지 동시성이나 병렬성 때문에 대해 고민할 필요성을 느끼지 못했습니다.
하지만 Python의 동시성과 병렬성에 대해 찾아보면서 지금까지 써왔던 Node.js의 비동기 처리와 비교하며 이해하는 것이 편해 함께 찾아본 내용을 기록으로 남깁니다.
I/O 바운드(네트워크·디스크) 에 매우 효율적. 사용자 코드는 블로킹 호출만 피하면 높은 처리량을 낼 수 있다.
CPU 바운드 연산은 이벤트 루프를 블로킹한다 → worker_threads 로 분리하거나 네이티브 애드온으로 우회해야 한다.
함수나 라이브러리에 따라서 실행 결과를 Promise로 반환하는 방식을 사용하기도 하고, 결과를 인자로 넘긴 콜백을 호출해 알려주기도 한다.
async / await는 Promise를 활용하기 때문에 콜백 기반의 API에 await를 사용하고 싶다면 Promise로 래핑하는 과정이 필요하다.
콜백은 매크로 태스크로 큐잉되고, Promise가 resolve된 결과는 마이크로 태스크로 큐잉 되어 동작 순서에 영향을 미치는 등의 차이가 있다.
콜 스택이 비었을 때 이벤트 루프가 다음 작업을 선택하는 규칙은 생각보다 규칙이 많아서 다음 기회에 정리하고자 합니다.