js는 왜 싱글 스레드인가?

상태
진행 중
담당자
날짜
TMI

JavaScript는 왜 싱글 스레드인가?

JavaScript는 왜 싱글 스레드인지 알아보자.

프로세스와 스레드 정의

왜 싱글 스레드인지 알아보려면 ‘스레드’가 무엇이고 더 나아가 ‘프로세스’가 무엇인지 알아야한다.
프로세스
컴퓨터에서 실행중인 프로그램을 의미한다.
스레드
프로세스 내에서 실행되는 작은 실행 단위이다. 하나의 프로세스는 하나 이상의 스레드를 포함할 수 있고 프로그램 환경에 따라 둘 이상의 스레드를 포함할 수 있다.

싱글 스레드란?

스레드의 정의를 알아봤으니 싱글 스레드가 무엇인지 알아보자.
하나의 주 실행 경로(Main Thread)에서 모든 작업을 처리하는 방식을 말한다.
이는 프로그램이 동시에 여러 작업을 수행할 수 없음을 의미한다.
js에서 코드가 순차적으로 실행되며, 다음 작업이 실행되기 전에 이전 작업이 완료되어야함을 의미한다.
그렇다면 싱글 스레드의 장단점은 무엇이 있을까?

싱글스레드의 장점

1.
자원 접근에 대한 동기화를 신경쓰지 않아도 된다.
다수의 스레드(멀티 스레드)가 프로세스의 자원을 공유할 경우, 각 스레드가 원하는 결과를 얻게 하려면 공용 자원에 대한 접근을 제어하는 소요가 필요하다.
모든 스레드가 일정 자원에 동시에 접근하거나, 같은 작업을 실행하려는 경우 별도로 처리를 해줘야하고 제어해줘야한다.
이러한 점들 때문에 싱글 스레드는 업무에 대한 소요가 적고 비용 절감 효과가 있는 것이 장점이다.
2.
문맥 교환 작업을 요구하지 않는다.
문맥 교환 작업 : 여러 개의 프로세스가 하나의 프로세서를 공유할 때 발생하는 작업으로 많은 비용을 필요로 한다.
3.
메모리 효율성이 좋다.
스레드를 여러 개 관리하지 않으므로 메모리 소비가 적다.
4.
동기적 코드의 흐름
작업이 순차적으로 실행되기 때문에 코드의 실행 순서를 예측 가능하고 관리하기 쉽다.

싱글 스레드의 단점

1.
성능 제약
싱글스레드는 대규모연산이나 복잡한 계산을 동시에 처리하기 어렵다.
2.
동시성이 부족하다.
싱글 스레드 환경에서는 병렬 처리가 제한되어 하나의 스레드만 동작하므로 여러 작업을 병렬로 처리할 수 없으며, 모든 작업이 순차적으로 실행된다.
3.
CPU의 다중 코어 활용을 제한
단일 프로세스 내에서만 동작하기 때문에 CPU의 모든 코어를 활용하지 못한다.

JavaScript에서의 싱글 스레드

싱글 스레드에 대해서 알아보았으니 JavaScript에서 싱글 스레드를 왜 쓰는지 알아보자.
1.
웹 브라우저 환경
JavaScript는 웹 브라우저의 구조상 메인 스레드에서 실행한다.
웹 페이지의 중요한 구성 요소들(HTML, CSS, JavaScript)을 처리하는 메인 스레드는 이벤트 처리, 렌더링, 사용자 입력 처리 등 여러 가지 작업을 동시에 처리해야 한다. 이러한 다양한 작업들을 순차적으로 처리하면서 웹 페이지의 렌더링을 지연시키지 않기 위해 js는 싱글 스레드로 설계되었다.
2.
이벤트 기반 비동기 처리
JavaScript는 비동기적인 이벤트 기반 프로그래밍 모델을 채택하고 있다. 이는 특정 이벤트가 발생했을 때 콜백 함수를 호출하여 처리하는 방식이다.
예를 들어, 사용자가 버튼을 클릭하거나 네트워크 요청이 완료될 때까지 기다리지 않고 다음 작업을 수행할 수 있도록 한다.
이러한 비동기 처리 방식은 싱글 스레드 환경에서 효율적으로 동작할 수 있다.
비동기 이벤트 처리 : 버튼클릭
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>버튼 클릭</title> </head> <body> <button id="Button">클릭</button> <script src="button.js"></script> </body> </html>
HTML
복사
//button.js document.getElementById('Button').addEventListener('click', () => { console.log('버튼을 클릭했습니다!'); }); console.log('버튼을 클릭해주세요.');
JavaScript
복사
이벤트 리스너의 비동기성 원리
1.
즉시 실행되지 않는다 : 이벤트 리스너의 콜백 함수는 이벤트가 발생할 때까지 실행되지 않는다. 즉 이벤트 리스너는 즉시 실행되는 동기적 코드와는 달리 나중에 실행될 작업을 등록하는 것이다.
2.
이벤트 발생 시점과 무관하다 : 콜백 함수는 이벤트가 언제 발생할지에 관계없이 별도의 시간에 실행된다. 이는 이벤트 루프가 콜백 함수의 실행을 스케줄링하기 때문이다.
3.
동기화 문제 회피
여러 스레드가 동시에 데이터를 변경하거나 접근할 때 발생할 수 있는 경쟁 상태나 데드락같은 문제를 피하기 위함도 있다.
경쟁 상태(Race Condition) : 여러 스레드 또는 프로세스가 동시에 공유 자원에 접근하여 결과가 의도치 않게 변할 수 있는 상태를 말한다. 이로 인해 프로그램의 결과가 실행 순서에 따라 달라지게 되며, 의도하지 않은 버그나 예측 불가능한 행동이 발생할 수 있다.
데드락 : 두 개 이상의 스레드가 서로 자원이 풀리기를 기다리며 영원히 대기 상태에 빠지는 문제이다. 이로 인해 모든 스레드가 작업을 진행할 수 없어 시스템의 일부나 전체가 멈춘다.

웹 브라우저 외부 환경에서의 JavaScript

추가적으로 웹 브라우저 외부 환경에서 JavaScript를 사용할 수 있게하는 Node.js에서는 어떨까?
Node.js는 기본적으로 메인 스레드(싱글 스레드)에서 js코드를 실행한다.

Node.js란?

Node.js는 비동기 이벤트 기반 JavaScript 런타임이다. 이를 통해 서버 측 애플리케이션을 효율적으로 개발할 수 있다. 서버 측에서도 JavaScript를 사용할 수 있게하여 클라이언트와 서버에서 동일한 언어로 애플리케이션을 개발할 수 있는 장점이 있다.
Node.js는 기본적으로 싱글 스레드이지만 비동기 I/O와 이벤트 루프를 통해 높은 동시성을 제공한다.
1.
비동기 I/O 처리
Node.js에서는 대부분의 I/O 작업(파일 읽기/쓰기, 네트워크 요청등)이 비동기적으로 처리한다. 비동기 I/O는 작업을 요청한 후 즉시 반환하고 실제 작업이 완료되면 콜백 함수 또는 프로미스를 통해 결과를 처리한다. 이 방식은 CPU를 블로킹하지 않고 효율적으로 사용하게 한다.
2.
이벤트 루프
이벤트 루프는 비동기 작업의 콜백 함수들을 스케줄링하고, 콜백 함수들이 적절한 시점에 호출되도록 관리한다. 이를 통해 Node.js는 싱글 스레드에서 동시에 많은 작업을 처리할 수 있다.

결론

자바스크립트는 왜 싱글 스레드인지를 간략하게 정리하자면
자바스크립트는 웹 페이지의 여러 기능들을 수행하기 위해 브라우저에서 동작하는 경량 프로그래밍 언어로 설계하였기 때문이다.
멀티 스레드로 구현되는 서비스에서는 동시성 문제를 신경써야하기 때문에 소요가 크다
추가로 자바를 고려하였지만 멀티 스레드 + 무겁고 어려운 언어라는 인식 때문에 웹 개발자에게 더 최적화된 싱글 스레드 기반인 자바스크립트 언어를 개발하였다.