본 게시물은 JSConf의 어쨌든 이벤트 루프는 무엇인가? 를 참고하며 작성되었다. 다만 싱글 스레드에 대한 정확한 이해 없이는 콜스택과 큐가 뭔지, 웹 API는 왜 필요한지 등에 대해 기술하는 것이 시기상조라 생각되어 본 글을 먼저 작성한다.
https://www.youtube.com/watch?v=8aGhZQkoFbQ&t=89s
자바스크립트는 싱글 스레드(Single-thread) 언어다. 싱글은 하나, 스레드는 컴퓨터 프로세스 내에서 실행되는 작은 작업 단위를 말한다. 싱글 스레드는 이 두 개념을 합친 것으로 '한 번에 하나의 작업만 처리되는 환경'을 말한다.
하나에 하나의 작업만 처리 할 수 있다는 것은 일종의 제약이다. 하나의 작업이 끝나기 전까지는 다른 작업을 수행할 수 없다는 것을 의미하기 때문이다.
useToilet(first_person); // 첫 번째 사람이 화장실을 이용한다.
useToilet(second_person); // 두 번째 사람은 첫 번째 사람이 나오기 전까지 화장실을 이용할 수 없다.
앞의 작업이 길어져서 뒤의 작업이 실행되지 못하고 있는 것, 이것을 블로킹(Blocking) 이라고 한다.
"굳이" 더 복잡한 구조가 필요하지 않았기 때문이다.
자바스크립트가 등장한 초기에는 단순한 이벤트 기반 모델이 필요했다. 당시 웹 페이지와 애플리케이션은 주로 A라는 입력이 들어오면 B라는 출력이 되는 간단한 동작을 수행하는 것이었다. 이러한 상황에서는 싱글 스레드 모델이 코드를 단순하게 작성하고 유지보수하는 데에 도움이 되었다. 코드의 실행이 한 번에 하나의 작업만 처리되는 구조가 예측 가능하고 이해하기 쉬웠기 때문이다.
그러나 웹 기술이 진화하며, 동시에 브라우저에서의 요구사항과 복잡성 또한 증가했고, 싱글 스레드 모델의 한계가 나타나기 시작했다. 브라우저에서는 더 많은 동시성과 비동기 작업이 필요했고, 이에 대한 요구를 충족시키기 위해 멀티 스레드(Multi-thread)와 비동기 프로그래밍(Asynchronous Programming)이 중요해졌다. 자바스크립트는 이러한 환경에 대응하기 위해 발전하면서, 싱글 스레드의 제약을 극복하고 보다 복잡하고 효율적인 구조를 채택하게 되었다.
하나의 주방에서 여러 명의 요리사가 일하는 환경을 생각해 보자. 요리사들은 같은 공간에 있기 때문에 재료를 공유할 수 있으며, 한 번에 하나의 요리가 아닌 여러가지 요리를 동시에 할 수 있기 때문에 효율적이다.
"환경은 멀티 스레드, 요리사는 스레드, 주방은 프로세스, 그리고 재료는 리소스라고 생각하면 된다."
정리하자면, 멀티스레드 환경에서 여러 스레드들이 하나의 프로세스 안에서 함께 일하며 리소스를 공유하는 것이다.
그런데 같은 재료를 두 명의 요리사가 동시에 집으려고 할 때, 손이 꼬이거나 할 수 있다. 이것을 경쟁 조건(Race condition) 이라고 한다. 이때 요리사들은 사고를 방지하기 위해 규칙을 세운다. 만약 동시에 같은 재료를 원한다면, 누가 먼저 쓰고, 다음에 누가 쓸지 정하는 것이다. 이것이 바로 동기화 메커니즘(Synchronization Mechanism)이다. 두 스레드가 하나의 공유 자원에 동시에 접근할 때, 예상치 못한 에러를 방지하기 위해 사용하는 순차적 작업 규칙이라고 이해하면 된다.
"다른 개념이다."
환경(Environment)과 동작(Behavior)의 차이로 이해하면 된다. 싱글 스레드와 멀티 스레드는 어플리케이션의 실행 환경에 관한 것이고, 동기와 비동기는 작업 완료와 프로그램의 제어 흐름에 관한 것이다.
싱글 스레드 환경에서 비동기 작업을 처리할 때, 주로 웹 API나 외부 서비스에 요청을 보내고 그 요청에 대한 응답을 기다리지 않고 다른 작업을 계속한다. 이때 싱글 스레드의 비동기 작업은 외부 에서 처리된다고 볼 수 있다. 즉, 추가 주문이 들어오면 요리사가 외부에서 뒷 주방 요리사를 고용하는 것과 유사하다.
싱글 스레드 환경에서는 여러 명이 함께 일하는 것이 어렵고, 필요하다면 외부에서 자원을 끌어와야 하는 제약이 있다. 이것이 싱글 스레드의 특징이다. 요리사가 한 번에 하나의 음식을 만들고, 그 다음에 다른 음식을 만드는 것은 동기적인 동작에 해당하며, 앞 주방 요리사가 요리를 하는 동안 뒷 주방 요리사가 다른 요리를 만들고 완료되면 앞 주방 요리사에게 넘겨주는 것이 비동기적인 동작이다.
멀티 스레드는 다르다. 이 환경에서는 웹 API나 외부 서비스의 도움이 필요하지 않고, 멀티 스레드 간의 협력과 조율에 의해 작업을 처리할 수 있다. 이미 여러 명의 요리사가 한 주방에서 일할 수 있는 환경이기 때문이다. 이는 멀티 스레드가 각각의 작업을 독립적으로 처리(동기)하면서도 필요한 경우에는 서로 협력하여 효율적으로 작업을 수행할 수 있다는 것(비동기)을 의미한다.