본문 바로가기
CS

이벤트 루프(Event Loop)란?

by eddypark 2024. 8. 21.

이벤트 루프(Event Loop)를 알려면 우선 자바스크립트(JavaScript)에 대해 알아야 한다.

 

자바스크립트는 싱글 스레드 프로그래밍 언어(Single Thread Programming)이다.


즉, 싱글 스레드 런타임(Single Thread Runtime)을 가지고 있다는 말인데 이것은 한 번에 하나의 싱글 콜 스택(Single Call Stack)만을 가지고 있다는 말이다. 이 의미는 싱글 스레드라는 의미이며 하나의 프로그램은 동시에 하나의 코드만 실행할 수 있다는 것이다. (one thread == one call stack == on thing at a time)

 

방금 말한 내용을 시각화해 보면 다음과 같다.

제곱을 보여주는 함수

콜 스택은 data Structure로 실행되는 순서를 기억하고 있다. 따라서 함수를 실행하려면 스택(Stack)에 해당하는 함수를 집어넣고 함수에서 리턴이 일어나면 스택의 가장 위쪽에서 해당 함수를 꺼내게 된다. 이게 콜 스택의 전부이다.

 

위에서 보여준 함수를 예시로 들어보면 실행되는 함수의 순서에 맞게 stack에 들어가게 된다.

Stack에 쌓인 함수

 

아래의 이미지는 또 다른 예시이며 두 번째 이미지는 잘못된 콜 스택의 예시이다. 

 

그렇다면 프로그램에서 무엇이 느리게 할까? 당연히 느리게 동작하는 코드가 있으면 프로그램은 느릴 것이다. (네트워크 요청이나 이미지 프로세싱(Image Processing), console.log 자체는 느리지 않지만 반복문 안에 수십억 번의 console이 있다면 느린 것처럼) 그리고 이렇게 느린 동작이 스택에 남아있는 것을 보통 블로킹(Blocking)이라고 한다.

예를 들어보자

동기적으로 Ajax 요청을 보내는 jquery 함수 getSync가 있다고 한다면 어떤 식으로 동작할까?(비동기 생각은 잠시 접어두자)  하나의 요청을 보내고 완료될 때까지 시간이 소요될 것이다. 네트워크가 빠르면 다행이지만 만약 각 요청이 한 시간이 걸린다면 이 간단한 예시는 총 3시간이 걸리게 된다.

 

이것이 문제가 되는 이유는 브라우저에서 이 코드를 실행한다는 것이다. 그렇다면 사용자는 총 3시간이 지나기 전까지는 아무것도 하지 못한다. 왜냐하면 콜 스택에 어떤 것들이 남아 있으면 네트워크 요청이 콜 스택을 블로킹하기 때문이다. 따라서 우리는 콜스택을 멈추게 해서는 안된다.

 

이 문제에 대한 해결 방법은 무엇일까? 가장 간단한 방법은 비동기 콜백이다. 코드를 실행하면 결국 콜백을 받고 이걸 나중에 실행한다는 말이다. 브라우저 같은 것은 실제로 대부분 비동기로 만들어져 있다. 

간단한 비동기 콜백의 예시를 보자

이 예시의 결과는 hi -> JSConfEU -> there 순으로 나올 것이다. 그리고 스택이 쌓이는 순서는 아래의 이미지와 같다.

뭔가 이상해 보인다. 분명 setTimeout이 리턴되면서 hi -> there  -> JSConfEU 순으로 나와야 하는 것처럼 보인다. 여기서 이벤트 루프와 동시성이 역할을 하게 된다.

 

분명 자바스크립트는 싱글 스레드 언어라고 했는데 멀티 스레드인 것처럼 보인다. 하지만 싱글 스레드 언어가 맞다.

그 이유는 브라우저에서 Web API와 같은 것들을 제공해 주기 때문이다. 이러한 것들은 호출할 수 있는 스레드를 효과적으로 지원한다. 여기에 동시성 개념이 들어오는 것이다. 예시를 보자.

이전의 예시와 같이 setTimeout이 스택에 담긴 상태이다. setTimeout은 자바스크립트가 실행되는 런타임 환경에 존재하는 별도의 API이다. 따라서 브라우저가 타이머를 실행시키고 카운트 다운을 시작한다.

이 의미는 setTimeout의 호출 자체는 완료되었다는 의미로 스택에서 함수를 지울 수 있으며, 그다음 순서인 console.log('JSConfEU')까지 실행하게 된다.

5초가 지나면 WebAPI는 작동이 완료되지만 갑자기 스택에 넣는 것처럼  갑자기 작성된 코드에 끼어들 순 없다.  이때 활용되는 것이 테스크 큐(task queue)와 콜백 큐(callback queue)이다.

모든 Web API는 작동이 완료되면 콜백을 테스크 큐에 밀어 넣는다.

자 이제 이 글의 주제인 이벤트 루프를 설명할 차례이다. 이벤트 루프란 무엇이며 무슨 역할을 할까? 콜 스택과 테스크 큐를 주시하는 역할을 한다. 스택이 비어있으면, 큐의 첫 번째 콜백을 스택에 쌓아 효과적으로 실행할 수 있게 하는 것이다.

현재 예시를 보면 스택은 비어 있으며 테스크 큐에 콜백이 쌓여있다. 이제 이벤트 루프가 콜백을 스택에 넣어준다.

드디어 우리가 생각했던 결과대로 출력이 된다. 그렇다면 만약 setTimeout 시간을 0초로 한다면? 방금과 같은 비동기 함수의 동작을 모른다면 Hi -> there -> JSConfEU로 예상할 것이다. setTimeout이 0초라 바로 실행된다고 생각할 테니까. 하지만 이벤트 루프는 스택이 비워져 있어야 스택에 넣기 때문에 결과는 Hi -> JSConfEU -> there로 나온다.

모든 이런 종류의 Web API는 동일한 방식으로 작동한다. 따라서 아래의 예시도 역시 Hi -> JSConEU -> data 순이다.

 

따라서 스택에 오래 걸리는 코드를 쌓아 브라우저가 작동 못하게 하지 말고 유동적으로 이벤트 루프를 활용해야 한다.

 

아래의 링크는 이벤트 루프를 시각화 해주는 사이트이다.

 

http://latentflip.com/loupe/?code=JC5vbignYnV0dG9uJywgJ2NsaWNrJywgZnVuY3Rpb24gb25DbGljaygpIHsKICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gdGltZXIoKSB7CiAgICAgICAgY29uc29sZS5sb2coJ1lvdSBjbGlja2VkIHRoZSBidXR0b24hJyk7ICAgIAogICAgfSwgMjAwMCk7Cn0pOwoKY29uc29sZS5sb2coIkhpISIpOwoKc2V0VGltZW91dChmdW5jdGlvbiB0aW1lb3V0KCkgewogICAgY29uc29sZS5sb2coIkNsaWNrIHRoZSBidXR0b24hIik7Cn0sIDUwMDApOwoKY29uc29sZS5sb2coIldlbGNvbWUgdG8gbG91cGUuIik7%21%21%21PGJ1dHRvbj5DbGljayBtZSE8L2J1dHRvbj4%3D

 

latentflip.com

 

 

'CS' 카테고리의 다른 글

프론트엔드 관련 CS  (1) 2024.08.13