프로세스와 스레드 & 자바스크립트의 동작방식

HELLO WORLD🙌·2020년 8월 15일
3

TIL

목록 보기
17/23

프로세스

프로세스는 컴퓨터 위에서, 즉 운영체제 위에서 연속적으로 실행되고 있는 프로그램을 말한다. 음악 재생 프로그램이나 사진뷰어 프로그램 등 이런것들 하나하나 각각의 프로세스를 가지고 있다.

각각의 프로세스는 메모리 위에서 서로 독립적으로 실행된다.
만약 어떤 프로세스에서 문제가 발생하면 그 프로세스만 죽게된다. 각각의 프로세서는 저마다 리소스 자원들, 즉 할당된 메모리나 데이터들이 지정되어져있다.

그 프로세스 안에는 프로그램을 위해서 작성된 Code가 들어있고, 그 프로세스 안에서 함수들이 어떤 순서로 실행되어야하는지 이 함수가 끝나면 어디로 돌아가야되는지에 대한 정보가 들어있는 Stack이 들어있고,
우리가 오브젝트를 생성하거나 데이터를 만들 때 그 데이터들이 저장되는 공간인 Heap이 있다. Heap에는 동적으로 할당된 변수들이 저장되는 반면, Data에는 전역 변수나 스태틱 변수들이 할당되어진다.

스레드


한 프로세스 안에는 여러 개의 쓰레드가 동작할 수 있다. 쓰레드는 각각 저마다 해야되는 업무를 배정받는다. 이 쓰레드는 자기들만이 수행해야 되는 함수의 호출을 기억해야 되기 때문에 스레드마다 스택이 할당되어져 있다. 하지만 이 프로세스 안에서 동작하는 쓰레드들은 결국은 한 프로그램을 위해서 일해야되므로 프로세스에 지정된 코드와 데이터, 힙들을 공통적으로 접근해서 공통적으로 업데이트가 가능하다.

즉, 내 프로그램에서 음악을 들으면서 사진을 편집할 수 있는 어플리케이션이 있다면 음악재생하는 쓰레드 하나, 사진 편집하는 쓰레드 하나, 음악 데이터를 서버에서 받아와 처리하는 쓰레드 하나.. 이런 식으로 저마다 처리한다. 이렇게 동시다발적으로 발생할 수 있기 때문에 이 프로세스가 좀 더 효율적으로 일할 수 있도록 도움을 준다.

자바스크립트의 동작방식

자바스크립트는 싱글스레드로 작동한다.

자바스크립트에는 멀티스레딩을 할 수 있는 방법이 없지만, 이 자바스크립트가 동작하고 있는 브라우저에는 여러가지의 쓰레드가 들어있다. 그래서 브라우저의 웹APIs 들을 이용하게 되면 멀티쓰레딩이 가능해지는 것이다.
그리고 자바스크립트가 동작하는 런타임 환경에서 이벤트루프를 이용해 멀티스레딩 같은 효과를 얻을 수가 있다.

웹 어플리케이션이 브라우저에 올라가는 순간 자바스크립트 엔진이 작성한 소스 코드를 한 줄 한 줄 해석하고 실행하게 된다. 자바스크립트 엔진의 구조는 간단하게 크게 메모리힙과 콜스택으로 나눠져 있다.

  • 메모리힙 : 우리가 데이터를 만들 때, 즉 변수를 선언해서 오브젝트를 할당하거나 문자열이나 숫자를 할당하게 되면 그 데이터들은 전부 다 메모리힙에 저장이된다. 구조적으로 정리된 자료구조가 아니라 아무곳에서 저장되어진다.
  • 콜 스택: 우리가 함수를 실행하는 순서에 따라서 차곡차곡 쌓아놓는 것. LIFO 제일 나중에 들어온 것이 제일 처음으로 나가는 자료구조를 가지고 있다. 스택에는 push와 pop같은 API들이 있다.
    함수들이 호출하는 순서를 기억했다가 함수가 끝나면 원래 있던 자리로 돌아가기 위해서 쓰이는 자료구조 중 하나이다. 모든 프로세스와 스레드안에는 각각 저마다의 콜스택이 들어있다.

어떻게 웹 APIs와 자바스크립트엔진이 함께 동작하는 것일까?

어떤 함수에서 setTimeout을 호출 하여 3초 후 ‘hello’라는 콘솔을 출력하는 콜백 함수를 등록했다고 가정해본다면, setTimeout을 호출하는 순간 setTimeout 콜백에서 지워지고 web API로 보내져 타이머를 시작하게 된다. 이렇게 타이머가 실행되는 동안에도 자바스크립트 엔진은 병렬적으로 실행이 되고 있다가 지정된 시간이 끝나면 웹 APIs는 태스크 큐에 콜백자체를 태스크 큐에 집어 넣는다.
그 후 이벤트루프가 스택이 비워져 있는지 확인한 후 스택으로 콜백을 보낸다.

이벤트루프란?

이벤트루프가 하는 일은 queue의 첫번째 있는 작업을 stack이 비워져있는지 확인한 뒤 작업을 stack으로 보내는 역할을 하는 것이다.

  • Tsk Queue에는 우리가 등록한 콜백함수들이 들어온다. 먼저 들어온게 먼저 나가는 FIFO 자료구조를 가지고있다.
  • Microtask Queue는 프로미스를 쓰면 그 프로미스에 등록된 콜백이 들어온다
  • Render는 브라우저에서 우리가 변형한 코드가 주기적으로 업데이트 되기 위해서 주기적으로 호출되는 순서인데, 애니메이션 프레임이라는 API를 부르면 그때 등록한 콜백이 이 리퀘스트 애니메이션 프레임 큐에 차곡차곡 쌓인다.

이벤트루프는 태스크큐-콜스택-렌더-마이크로태스크큐 를 계속 순회한다.

  1. 콜스택에 무언가 있다면 (수행중인 함수가 있다면) 그 함수가 끝날때까지 머물러있다.
  2. 콜스택이 하나씩 다 처리되어 비워지면, 렌더 쪽으로는 갈 수도 있고 안갈 수도있다. 브라우저에서는 사용자에게 60f/s 속도로 보여주는데, 이벤트루프는 그 속도보다 훨씬 빠르기때문에, 그떄마다 렌더를 업데이트할 필요가 없기때문이다.
  3. 마스크로 태스크 큐로 넘어오면, 큐 안에 있는 콜백을 콜스택에 넣고, 콜스택에서 처리하면 다시 마이크로태스크큐 안에 있는 다른 콜백을 콜스택에 넣고, 이런식으로 마이크로태스크큐가 전부 비워질떄까지 계속 콜스택으로 가져와 수행한다.
  4. 마이크로태스크큐가 텅 비워진 후에야, 이벤트루프가 다시 순회를 재개한다. 그 다음 태스크 큐에서는 한번에 딱 하나의 콜백만 콜스택으로 가져온다. 그 함수가 다 끝나면 다시 순회를 시작한다.
  5. 브라우저에 업데이트를 할 타이밍이 되면 렌더시퀀스에 들어간다.
    먼저 리퀘스트 애니메이션 프레임을 통해 등록된 콜백함수들을 전부 실행한후, 렌더트리를 만들고, 그 트리를 이용해 레이아웃을 계산하고, 페인트를 통해 브라우저에 업데이트를 한 후 다시 이벤트루프를 돈다.

0개의 댓글