[CS] 싱글 스레드

서론

실무에서 웹캠과 Google AI 라이브러리인 MediaPipe를 이용해 객체(사용자) 인식을 수행하고, 이를 백엔드로 전송하는 작업을 진행했다.

Mac OS 환경에서는 문제없이 실행되었지만, 키오스크(Windows) 환경에서는 심각한 스레드 부하가 발생했다.
이로 인해 연산이 수행되는 동안 버튼이 클릭되지 않는 현상이 나타났다.

경량화된 라이브러리를 사용해 최적화를 시도했지만, 여전히 동일한 문제가 발생했다.
Lighthouse를 통해 키오스크 성능을 분석한 결과, Performance 점수가 27점에 불과했고, CPU 사용량이 거의 100%에 도달하는 것을 확인할 수 있었다.

이 경험을 통해 컴퓨터 사양에 따라 최적화 방법이 달라질 수밖에 없다는 점을 실감했고, 이에 따라 스레드 부하를 줄이는 방법을 고민하게 되었다. 이런 결과로 스레드에 대해 알아보고자 한다.


결국, 필자는 실시간 영상에서 객체 인식을 수행하는 대신, 일정 간격으로 캡처된 이미지를 이용해 객체를 판별하는 방식으로 과부하를 줄이는 해결책을 찾았다.

충격적인 LightHouse

 

1. Javascript 싱글 스레드란?

자바스크립트(JavaScript)는 싱글 스레드(Single Thread) 기반의 언어다. 즉, 한 번에 하나의 작업만 실행할 수 있다.
이러한 특성 때문에 연산량이 많은 작업이나 비동기 처리에서 성능 이슈가 발생할 수 있다.

이러한 구조는 브라우저 환경에서 UI 업데이트를 방해하지 않도록 설계된 것이지만,
무거운 연산이 필요한 작업에서는 오히려 성능 저하의 원인이 된다.

 

특징

  • 하나의 메인 실행 흐름(Main Thread)이 존재
  • 한 번에 하나의 작업만 실행 가능
  • 다음 코드가 실행되려면 이전 코드가 끝나야 함

 

2. 싱글 스레드에서 발생하는 문제 – 스레드 부하(Thread Load)

JavaScript는 하나의 스레드에서 모든 연산을 처리하기 때문에 스레드 부하(Thread Load)가 발생할 수 있다.

스레드 부하가 발생하는 상황

  1. CPU 집약적인 연산
    • 복잡한 수학 계산, 암호화, 대량의 데이터 처리
  2. 동기 코드(Blocking Code)
    • 하나의 작업이 끝날 때까지 다음 작업이 대기
    • 예: while(true) {} 같은 무한 루프
  3. I/O 작업이 많은 경우
    • 네트워크 요청, 파일 읽기, 데이터베이스 조회

 

문제가 발생하면 UI가 멈추고, (예: 웹사이트가 먹통이 됨), 이벤트 리스너가 응답하지 않음 (예: 버튼을 눌러도 반응 없음), 전체적인 성능 저하 등 상 사용자 경험에 굉장히 큰 이슈를 가져다 준다.

 

출처: 자바스크립트는 멀티스레드 일지도? ❘ Web Workers 웹 워커<별코딩>

필자가 겪은 상황과 동일한 상황이며, 동영상에서 이벤트가 발생하여 연산을 실행하는 동안 브라우저 다른 버튼들이 클릭이 안되는 성능 이슈가 발생하였다.

 

3. 스레드 부하를 줄이는 방법

(1) 비동기 처리 (Async/Await, Promise) 활용

싱글 스레드 환경에서 스레드 부하를 줄이려면 블로킹(blocking)을 최소화해야 한다.
이를 위해 JavaScript는 비동기 처리(Asynchronous Processing)를 지원한다.

// 비동기 API 호출 (Blocking 방지)
async function fetchData() {
  const response = await fetch("https://api.example.com/data");
  const data = await response.json();
  console.log(data);
}

fetchData();
  • 네트워크 요청이 끝날 때까지 메인 스레드를 점유하지 않음
  • 다른 작업이 동시에 실행될 수 있음

 

(2) Web Worker 사용 – 멀티스레드 활용

JavaScript는 기본적으로 싱글 스레드지만, Web Worker를 사용하면 멀티스레드처럼 처리 가능하다.
Web Worker는 메인 스레드와 분리된 백그라운드 스레드에서 작업을 실행할 수 있다.

// worker.js (웹 워커 파일)
self.onmessage = function (event) {
  let result = 0;
  for (let i = 0; i < event.data; i++) {
    result += i;
  }
  self.postMessage(result);
};

// main.js (메인 스레드)
const worker = new Worker("worker.js");
worker.postMessage(1000000000); // 연산 작업을 Web Worker에 전달

worker.onmessage = function (event) {
  console.log("연산 결과:", event.data);
};
  • 무거운 연산을 메인 스레드에서 분리하여 실행
  • UI가 멈추지 않고 부드럽게 유지됨

 

 

 

참조

자바스크립트는 멀티스레드 일지도? | Web Workers 웹 워커

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers