브라우저의 이벤트루프는 별도의 스레드가 존재할까요?

hoonsbory·2023년 5월 31일
2
post-thumbnail

자바스크립트는 싱글 스레드 언어입니다.

그렇기 때문에 코드를 병렬로 처리할 수가 없습니다.

이를 보완하기 위해 자바스크립트 런타임인 브라우저에서 이벤트루프가 도입되었습니다.

자바스크립트의 setTimeout 같은 비동기 함수는 Web API 스레드에서 별도로 처리됩니다.

이벤트 루프는 콜스택을 감시하다가 콜스택이 비워지면 Task Queue에 있는 콜백 함수를 콜스택에 Push하는 것으로 알려져 있습니다.

그렇다면 이벤트 루프 또한 별도의 스레드가 존재하는걸까요?



아닙니다. 이벤트 루프는 메인스레드 위에서 작동합니다.

그런데 어떻게 싱글 스레드에서 2가지 일(코드 실행 + 콜스택 비었는지 감지)을 한번에 할 수 있을까요?

사실 한번에 하는 것처럼 보이지만 그렇지 않습니다.

이벤트 루프가 콜스택을 감시한다는 것 부터가 잘못된 말입니다.

흔히 '감시한다'는 표현은 브라우저의 이벤트와 같습니다.

클릭, 스크롤 등의 입력 이벤트들은 브라우저의 별도의 스레드에서 이벤트를 감지하여 콜백함수를 Task Queue에 넣는 방식으로 구현되어있습니다. (브라우저의 입력 이벤트 동작 원리는 해당 링크를 참조해주세요 )

하지만 이벤트 루프는 콜스택(V8)과 같은 메인스레드에서 동작하기 때문에 따로 이벤트를 등록하여 감시할 수 없습니다.

즉, 콜스택을 주시한다, 감시한다 라는 표현은 사실 옳지 않습니다.


그럼 이벤트 루프는 어떻게 구현되어 있을까요?

void MessagePumpDefault::Run(Delegate* delegate) {
  AutoReset<bool> auto_reset_keep_running(&keep_running_, true);

  for (;;) {
#if defined(OS_APPLE)
    mac::ScopedNSAutoreleasePool autorelease_pool;
#endif

    Delegate::NextWorkInfo next_work_info = delegate->DoWork();
    bool has_more_immediate_work = next_work_info.is_immediate();
    if (!keep_running_)
      break;

    if (has_more_immediate_work)
      continue;

    has_more_immediate_work = delegate->DoIdleWork();
    if (!keep_running_)
      break;

    if (has_more_immediate_work)
      continue;

    if (next_work_info.delayed_run_time.is_max()) {
      event_.Wait();
    } else {
      event_.TimedWait(next_work_info.remaining_delay());
    }
    // Since event_ is auto-reset, we don't need to do anything special here
    // other than service each delegate method.
  }
}

Chromium의 이벤트루프 코드 중 일부입니다. (이벤트 루프 구현은 브라우저마다 다르고 매우 복잡합니다.)

keep_running이라는 플래그 변수를 통해 이벤트 루프의 반복문을 break하는 것을 볼 수 있습니다.

이걸로 유추할 수 있는 사실은 이벤트 루프는 무한으로 돌아가지 않는다는 겁니다.

이처럼 이벤트 루프는 무한으로 돌아가면서 콜스택이 비어있는지 감시하는 것이 아닌, 콜스택이 비워질때 실행되며, 특정 조건에 의해 종료됩니다.


이벤트 루프는 V8 엔진에 포함되어 있지 않습니다. 그렇기 때문에 ECMAScript 명세에도 존재하지 않습니다.

V8과 이벤트 루프는 모두 Blink엔진 안에 있습니다. Blink의 하나의 메인스레드에서 콜스택과 이벤트 루프가 관리됩니다.
그렇기 때문에 콜스택이 전부 비워져야만 이벤트 루프에서 콜백함수를 콜스택에 push하도록 설계된 겁니다.

결론 => 이벤트 루프는 별도의 스레드가 아닌 메인스레드에서 특정시점마다 작동하는 Loop입니다.


다음에는 직접 이벤트 루프를 자바스크립트로 구현해보면서 싱글스레드에서 어떤식으로 동작하는지 알아보겠습니다.

1개의 댓글

comment-user-thumbnail
2023년 8월 19일

이처럼 이벤트 루프는 무한으로 돌아가면서 감시하는게 아니라니.. 충격이네요..
어찌 보면 당연한 얘긴데 깊게 생각하지 못했던 부분이었던 것 같습니다. 짚어주셔서 감사합니다.
Blink 엔진이라는 좋은 키워드를 얻었으니 한 번 더 공부해봐야겠네요.
항상 좋은 글 감사합니다.

답글 달기