• Home
  • About
    • Pieces for Studying photo

      Pieces for Studying

      Moon is a minimal, one column jekyll theme.

    • Learn More
    • Email
    • LinkedIn
    • Github
  • Posts
    • All Posts
    • Baekjoon
    • CS231N
    • Study
  • Projects

노드는 정말 싱글스레드로 작동할까 ?

07 Oct 2020

Reading time ~2 minutes

노드는 정말 싱글스레드로 작동할까 ?

만약 노드를 모르거나 노드의 작동방식을 알고싶다면 this article을 참고하세요.

대부분의 노드 설명글은 노드를 single-threaded라고 소개합니다. 다음은 노드의 멀티쓰레드와 관련된 오해들입니다.

  • 자바스크립트와 같이, 노드는 멀티스레딩을 지원하지 않는다.
  • 노드는 자바처럼 멀티쓰레딩에 적합한 언어이다.
  • 노드에는 두개의 쓰레드가 있으며, 하나는 이벤트루프에 대응하며 하나는 프로그램 실행을 담당한다.

이러한 것들은 오해라고 할 수 있는 가정들입니다. 사람들 종종 멀티쓰레딩과 멀티프로세싱, 쓰레드 풀, 그리고 운영체제가 어떻게 그것들을 관리하는지에 대해 헷갈릴 때가 있습니다.

  1. Process
    • 프로세스는 실행중인 프로그램입니다. 즉 프로그램이 실행되면 프로세스가 생성됩니다. 프로세스 하나는 여러개의 쓰레드(multi-threads)를 가질 수 있습니다.
  2. threads
    • 쓰레드는 프로그래밍 된 구문들의 가장 작은 시퀀스(순서?)로 운영체제의 스케줄러에 의해 독립적으로 관리됩니다.
  3. Multi-processing
    • 한개의 컴퓨터에서 두개 이상의 CPUs를 사용하는 것입니다. 이제, 멀티프로세서가 사용가능함에 따라 여러개의 프로세스들이 한번에 실행 될 수 있습니다.
  4. Multi-threading
    • 멀티 쓰레딩은 하나의 프로세스가 여러개의 Code block(쓰레드)를 가지고 프로세스의 context에 따라 동시에 실행되게 하는 실행 모델입니다.
  5. Thread Pool
    • 쓰레드 풀은 미리 생성된 쓰레드 그룹입니다. idle(유후) 상태의 쓰레드들은 주어진 작업을 실행하기 위해 대기합니다. 쓰레드 풀을 유지함으로 프로그램의 성능이 향상되고 실행 지연을 막을 수 있습니다.

노드 어플리케이션은 싱글 스레드로 작동하며 이벤트루프 또한 같은 스레드에 존재합니다. 따라서 우리는 노드가 싱글스레드라 말하지만 주목할 점은 노드에는 싱글스레드가 아닌 라이브러리들이 존재합니다.

예제의 도움을 통해 이해해보도록 합시다.

 const crypto = require("crypto");
const start = Date.now();

function logHashTime() {
  crypto.pbkdf2("a", "b", 100000, 512, "sha512", () => {
    console.log("Hash: ", Date.now() - start);
  });
}
logHashTime();
logHashTime();
logHashTime();
logHashTime();

노드의 crypto 모듈을 불러온 뒤 pbkdf2 함수를 4번 호출해 소요된 시간을 표시하였습니다.

결과를 보면, 4개의 logHashTime 함수는 실행되는 시간이 거의 동일합니다. 왜 4개의 함수들이 거의 비슷한 시간안에 실행 될 수 있을까요?

노드는 내부적으로 libuv라는 라이브러리를 사용합니다. 이 라이브러리는 운영체제와 관련된 작업들(비동기 IO, Networking, concureency 등)을 다루는데 사용됩니다.

Libuv는 OS-related 작업들을 수행하기 위해 모든 CPU 코어를 활용함으로써 4개의 쓰레드를 가진 쓰레드 풀을 설정합니다.

이것은 코어당 하나의 쓰레드를 생성하는 결과를 낳습니다. 이런 과정을 통해 모든 4개의 쓰레드는 logHashTime을 병렬적으로(in parallel) 실행합니다. 결과적으로 4개의 함수 실행에 비슷한 시간이 소요됩니다.

만약 두개의 CPU 코어밖에 없고, 많은 Operation을 수행하면 어떨까?

현재 컴퓨터에 4개의 코어가 있고, 앞의 코드를 logHashTime을 5번 실행하게 되면, 첫번째 4개의 함수 실행 소요 시간과 5번쨰 소요 시간은 차이가 존재합니다.

Libuv는 4개의 쓰레드를 가진 쓰레드 풀을 생성한 후 logHashTime을 4개의 CPU 코어에서 실행합니다. 쓰레드 중 하나라도 실행이 완료되면, 다섯번째 logHashTime을 실행하게 됩니다. 따라서 처음 4개의 함수 호출과 다섯번째 호출은 소요시간 차이가 발생하게 됩니다.

Libuv 쓰레드 풀의 쓰레드 숫자를 변경하고 싶다면?

우리는 한 줄의 코드를 작성함으로써 libuv의 쓰레드 수를 조정할 수 있습니다.

process.env.UV_THREADPOOL_SIZE =5;

해당 코드를 작성한 뒤 코드를 실행하면, 5개의 logHashTime 함수 실행 소요 시간이 거의 동일해집니다. 어떻게 가능했을까요?

모든 5개의 쓰레드는 4개의 CPU 코어 위에서 logHashTime을 실행하기 위해 노력합니다. 따라서 OS 쓰레드 스케줄러는 context swtiching의 도움을 받아 각 쓰레드가 실행을 끝내는 속도를 똑같이 맞춥니다.

Conclusion

우리는 노드는 싱글 스레드지만 백그라운드에서는 libuv 라이브러리의 도움을 받아 여러개의 쓰레드를 사용해 asynchronous한 코드를 실행한다는 것을 알 수 있습니다.

원본 글 https://medium.com/better-programming/is-node-js-really-single-threaded-7ea59bcc8d64



Study Share Tweet +1