멀티 태스킹이 가능하려면 프로세스의 동시성 (Concurrency)와 병렬성 (Parallelism) 특징을 각각 사용하거나, 혼합해서 사용해야 한다.
각 스레드마다 call stack이 존재하지만, 여러 스레드는 하나의 자원을 공유한다. 반면 프로세스는 프로세스마다 자원이 모두 다르다.
여러 스레드가 하나의 자원에 손을 대면 오류가 발생하게 된다. 이것이 멀티 스레드의 단점이다.
node.js의 Event loop는 싱글 스레드로 작동되지만, Worker pool은 멀티 스레드로 작동한다.
즉, node.js의 초기화와 callback은 Event loop라는 하나의 프로세스, 하나의 스레드에서 작동되지만 I/O intensive, CPU intensive한 모듈은 Worker pool에서 작동한다.
How Node.js really works
Node.js uses two kinds of threads: a main thread handled by event loop and several auxiliary threads in the worker pool.
Event loop is the mechanism that takes callbacks (functions) and registers them to be executed at some point in the future. It operates in the same thread as the proper JavaScript code. When a JavaScript operation blocks the thread, the event loop is blocked as well.
Worker pool is an execution model that spawns and handles separate threads, which then synchronously perform the task and return the result to the event loop. The event loop then executes the provided callback with said result.
In short, it takes care of asynchronous I/O operations — primarily, interactions with the system’s disk and network. It is mainly used by modules such as fs (I/O-heavy) or crypto (CPU-heavy). Worker pool is implemented in libuv, which results in a slight delay whenever Node needs to communicate internally between JavaScript and C++, but this is hardly noticeable. (https://blog.logrocket.com/a-complete-guide-to-threads-in-node-js-4fa3898fe74f/)