-
2023 - 06 - 27 이벤트 루프, 실행 컨텍스트, 호이스팅, 스코프체이닝, 프로세스, 싱글스레드, 논블로킹, 비동기, 동기 작업Today I Learned/TIL 06 2023. 6. 27. 10:51
이벤트 루프
컴퓨터는 하드웨어와 소프트웨어로 이루어져 있고, 소프트웨어에서 가장 중요한 프로그램 중 하나는 운영체제이다.
운영체제 (Operation System) 에서는, 사용자가 컴퓨터에게 일을 시키면 프로세스 (Process) 가 일을 한다.
프로세스는 OS로부터 CPU의 사용시간, 주소, 공간, 메모리 영역 등을 할당받는다.
그리고 프로세스는 그렇게 일을 할당받으면, 스레드 (Thread)라는 일을 한다.
멀티 스레딩, 싱글 스레딩, 멀티 프로세싱, 컨텍스트 스위칭등이 다 이 과정에서 일어난다.
Node.js 는 싱글 스레드 (Single Thread) 와 논 블로킹 (Non-Blocking) 을 사용한다.
논블로킹은 작업이 다른 작업을 차단하지 않고 비동기적으로 실행되는 방식을 의미한다. 논블로킹 작업은 결과가 도출될 때까지 다른 작업을 중단시키지 않고 계속 진행될 수 있다.
싱글스레드는 프로그램이 하나의 실행 스레드(thread)에서 작동하는 것을 의미한다. 즉, 작업들이 순차적으로 실행되며 한 번에 하나의 작업만 처리한다. 즉 싱글 스레드는 하나의 실행 흐름을 의미하며, 예를들어 파일 읽기와 같은 작업을 실행하면, 그 작업이 끝나기 전 까지 아무것도 할 수 없다.
하지만 Node.js에서는 싱글스레드(하나의 스레드)만으로 여러 비동기 작업들을 블로킹없이 (논블로킹으로) 사용할 수 있다. 그 기반에는 이벤트루프가 있다.
Node.js의 런타임 구성
Node.js의 런타임 구성은 코어와 바인딩, V8엔진, 그리고 4가지 요소 (Thead Pool, Event Pool, DNS, Crypto)로 구성되어 있다.
libuv는 Node.js의 핵심 라이브러리 중 하나로, 비동기 I/O 작업을 처리하고 이벤트 주도(event-driven) 프로그래밍을 지원하는 역할을 한다. Node.js는 단일 스레드로 작동하는데, libuv는 이 단일 스레드에서 다중 작업을 비동기적으로 처리하고 효율적인 I/O 작업을 가능하게 한다.
libuv의 작업 흐름
Node.js가 libuv에 비동기 요청을 하면, libuv는 현재 운영체제 커널에 작업이 가능한지 확인하고, 작업이 가능할경우 그대로 진행하여 Node.js에게 response를 보내지만, 그것이 불가능할 경우 자체 work thread가 담긴 스레드 풀에 요청을 보내, 작업 가능한 스레드에서 해당 요청을 처리하며, 다시 libuv에게 작업이 완료되었다고 알려주고, libuv는 node.js에게 작업완료 response를 보낸다. 또한 스레드풀은 작업 완료시에 파일시스템에 동기요청을 보낸다.
이런 과정으로, 노드는 비동기작업을 위해 외부의 어떤 장치(libuv)를 사용하고 있기 때문에 싱글스레드로 동작하지만 사실 싱글스레드로 동작하지 않는다. 스레드 풀에서 여러 스레드들이 있기 때문.이벤트 루프
Node.js에는 콜스택이라는 함수처리를 하는 메모리가 있다. 이 콜스택은 main과 setTimeout을 실행시킨다.
예를들어 setTimeout이 10초가 지나면 Background에서 타이머 실행되어 실행되어야 할 go 함수가 Task Queue에서 실행된다. 그러면 다시 Task Queue는 go 함수를 실행컨텍스트인 call stack에 보낸다, 이 모든 과정을 이벤트 루프라고 한다.
즉 이벤트루프란 비동기작업을 처리하고 실행순서를 관리하는 매커니즘이다.
ㅇㅇ
ㅇㅇThread 9
실행컨텍스트 (Execution Context)
자바스크립트를 실행하면 전역실행컨텍스트가 실행되며, 전체 파일을 한번 읽는다. 그리고 맨 윗줄부터 순차적으로 코드가 실행된다. 그리고 함수가 실행될 시 각 함수의 실행컨텍스트가 실행되게 된다.
그리고 각각의 실행컨텍스트 내부에는 각각 Variable environment와 Lexical environment가 존재한다.
참고 : https://sangwoorhie.tistory.com/50 https://sangwoorhie.tistory.com/49
실행컨텍스트에서 Environment Record (환경 레코드)에서는 자바스크립트의 식별자(변수)와 변경된 값을 저장하고 있고,
Outer Environment Reference (외부 환경 참조)에서는 현재실행되는환경보다 상위 환경, 상위 Lexical Environment (정적환경)을 참조한다. 어려운 말로 하면, 중첩된 자바스크립트 코드에서 식별자 탐색을 하는데 사용한다.
자바스크립트 실행 => 전역 컨텍스트부터 순차적으로 각 함수의 실행컨텍스트 실행 => 각각의 실행 컨텍스트에는 Environment Record (환경 레코드), Outer Environment Reference (외부 환경 참조) 이 있음.
이 때, 아래의 전역실행컨텍스트부터 위로 진행된다고 햇을때 가장 상단의 현재 실행되고 있는 함수 B실행컨텍스트가 현재 활성화된 컨텍스트이다. 그리고 함수가 실행되면 각 컨텍스트는 콜스택에서 제거된다.
호이스팅
자바스크립트의 실행 순서.
생성단계에서는 실행컨텍스트를 한번 읽고 선언문과 실행Record에 기록한다.
실행단계에서는 Record를 참조하여 업데이트한다.
이런 이유로 자바스크립트는 컴파일러 언어이며, 인터프리터 언어이다.
(컴파일러 언어 : 소스 코드를 컴파일러라는 특수한 소프트웨어를 사용하여 기계어나 중간 코드로 변환하는 방식으로 작동한다. 컴파일 과정에서 소스 코드는 전체적으로 분석되고 문법 오류를 확인하며, 정적으로 타입을 검사하고, 컴파일러는 이러한 분석된 소스 코드를 기계어로 변환하여 실행 파일을 생성한다. 이 실행 파일은 컴퓨터의 하드웨어에서 직접 실행되며, 실행 시간에 컴파일 과정은 필요하지 않다.)
(인터프리터 언어 : 소스 코드를 한 줄씩 해석하고 실행하는 특수한 프로그램인 인터프리터를 통해 작동한다. 인터프리터는 소스 코드를 실행하기 전에 한 줄씩 해석하며, 실행 시에 그때그때 해당 줄의 명령어를 해석하고 실행한다. 인터프리터 언어는 런타임에 코드를 직접 실행하기 때문에 컴파일 단계가 필요하지 않다.)
첫번째 줄 console.log(pizza)로 코드를 실행하면 실행컨텍스트가 생성된다.
생성단계에서 선언문을 레코드에 기록한다. 즉 pizza를 선언함과 동시에 undefined로 초기화하여 레코드에 기록한다.
실행단계에서 첫번째 코드가 실행되면 레코드(Record) 에서 피자를 참조해서 undefined를 출력한다.
두번째줄에서는 var로 변수 pizza를 combination이라고 선언한다. 그렇게 할 경우 record에서 업데이트된다. 더이상 피자는 undefined가 아니라 combination이다. 실행단계에서는 레코드를 참조 또는 업데이트하기 때문에 pizza: combination으로 업데이트 된다.
세번째줄 console.log(pizza)에서는 레코드에서 pizza를 갖고와서, pizza가 combination이라는 것을 나타내준다.
호이스팅은, 여기 첫번째줄에서 pizza가 선언되지 않았음에도 에러가 발생하지 않고 undefined라고 나왔는데 이것이 호이스팅이다. 레코드에서 undefined를 읽어온것이 호이스팅. 아직 선언되지 않았음에도 선언문이 마치 최상단에 끌어올려져있는 것처럼 같아보이는 현상.
변수선언문 var의 경우 선언을하면 바로 undefined로 초기화된다.
하지만 변수선언 let과 const는, 초기선언문이 없는상태에서 바로 console.log를 찍으면 reference error로 에러가 발생한다.
즉 선언 이전에 호출하게 되면 에러가 발생하게 되는데, 이런 구역을 일시적 사각지대(TDZ)라고 한다.
이러한 호이스팅 현상은 변수가 아닌, 함수에도 발생한다. 함수표현식 const, let에서는 코드 실행전에 함수를 호출하면 아무것도 참조할 것이 없기 때문에, reference Error가 발생한다.
함수 선언식의 경우에는 코드 실행전에 호출해도, 실행컨텍스트가 생성되고 레코드에서 읽어온다. 하지만 선언식의 경우에는 선언과 동시에 함수의 모든 내용을 레코드에 저장하기 때문에 에러없이 정상적으로 작동된다.
'Today I Learned > TIL 06' 카테고리의 다른 글
2023 - 06 - 29 데이터베이스 인덱스 (0) 2023.06.29 2023 - 06 - 28 REST API (0) 2023.06.29 2023 - 06 - 26 SQL 관계형 데이터베이스 일대일 관계, 일대다 관계, 다대다 관계 (0) 2023.06.26 2023 - 06 - 25 Json Web Token, Map함수 (0) 2023.06.25 2023 - 06 - 24 시퀄라이즈 (Sequelize), ORM, RDBMS (0) 2023.06.24