코드스피츠 85에서는 none blocking
에 대한 이야기와
자바스크립트를 짜는 근본적인 방법에 대한 고찰을 이야기해본다.
🌕🌑🌑
TL;DR
- 자바스크립트의 동시성 모델에 대해서 알아본다.
- 동시성이라는 단어를 이해하기 전에 병렬 모델을 먼저 알아본다.
- 병렬모델과 동시성 모델의 차이점은 워커가 하나 이상 있냐의 차이이다.
- 동시성 모델은 브라우저의 이벤트 루프와 테스크 큐를 예시로 알아보았다.
Concurrency 동시성
- 동시에 한다는 뜻이 아니라 시간을 쪼개서 진행한다는 뜻.
- ex. 이벤트 루프
1. Parallelism 병행성,병렬성
- 진짜로 2개를 동시에 하는 것
- 병렬성을 이해해야 동시성을 이해하기 쉬워서 다뤄본다.
1.1 예시_프론트에서 발견할 수 있는 병렬 처리는?
- 네트워크에 작업을 요청하면 병행처리가 일어남.
- 네트워크쪽 서버에도 프로세스가 진행되고 있음.
- 클라이언트도 다른 프로세스가 진행되고 있음.
1.2 핵심은
- 테스크에 할당되는 각각의 워커가 별도로 존재해서,
자기만의 속도와 자기만의 스케쥴에 따라서 일을 처리한다.
1.3 메모리의 개념과 함께 생각해보자
각각의 테스크가 같은 메모리를 바라볼 경우 문제가 생긴다.
즉, 동시성은 같이 쓰는 메모리를 어떻게 할지가 가장 어렵다.
- Blocking으로 해결한다.
- A가 선점하고 있는동안
Blocking
을 걸어서 다른 워커가 접근하지 못하도록한다. - 접근 못하는 워커는 메모리 접근을 위해 2가지 방법을 할 수 있다.
- 강제로 제어권을 뺏오는 방법
- 대기 한다.
- 언어에 따라 할 수 있는 방법이 다르다.
- ex. 자바: 오브젝트에 대기라는 방법은 사용하도록 wait라는 개념만 있다.
- 자바스크립트에서 동시성은..
- 자바스크립트 창조자는 ES2018까지 병행성 자체를 막아버렸다.
- ES2018 이후,
shared memory
와atomic
이라는 개념으로 병행성 가능해짐.
- 프로그래밍 패러다임 중
- 함수형 프로그래밍은 ‘공유를 하지마’로 해결한다.
- 객체지향 프로그래밍에서는 공유하는 메모리를 인정한다.
2. Concurrency
동시성에서 우리가 일을 시킬 수 있는 워커는 하나다.
- A에서 일을 조금 하고,
- A에 마킹을하고
- B에 가서 작업을 한다.
메모리를 동시에 쓰는 일이 없다.
우리가 보통 작업했던 자바스크립트는 한번에 메모리 블럭을 하나만 접근하기 때문에
여태까지 메모리에 대한 synchronized 문제를 어떻게 해결할지를 경험하지 않았다.자바스크립트는 병행성을 갖고 있지 않고, 동시성만 갖고 있다.
병행성과 동시성의 차이는
우리가 컨트롤 할 수 있는 워커가 몇 개 인가에 차이가 있다.
2.1 현실세계의 동시성
- 사람이 컨트롤하기에 동시성도 충분히 어렵다.
- 동시성에 대해서도 관심을 가지고 프로그래밍하지 않으면 복잡성이 올라간다.
- 동시성을 지원하는 다양한 자바스크립트의 메서드를 알아본다.
2.2 자바스크립트의 동시성
자바스크립트 엔진을 동시성 모델로 표현해보자.
- engine work: 브라우저 엔진은 초기 작업을 진행한다.
- 렌더링을 포함한 다양한 엔진이 수행해야하는 일들을 한다.
- 멀티스레드로 풀어서 초기 작업을 진행한다.
- engine이 일하는 내용이 우리의 자바스크립트 코드나 메모리에 영향을 미치기때문에 싱글스레드 안에 들어오려고 동시성 패키지안에 들어와있는 것 뿐.
- 크롬은 백그라운드 thread에서 수많은 일을 함
- queue를 체크한다. (ex. 이벤트 루프)
- 자바스크립트 명령어를 적재해 놓은 것이 있냐 없냐를 체크한다.
- queue는 callback queue(테스크 큐)를 바라본다.
- 브라우저에 로딩한 스크립트, 이벤트 리스너, ajax에 걸어놓은 완료 리스너도 다 콜백 큐에 들어간다.
- 콜백을 실행한다.
콜백 큐를 검사해서, 큐에 이번에 실행할 명령이 있는지 확인해서 꺼내서 실행하고 실행한 콜백큐를 제거한다.
실행 이후에는 다시 렌더링을 진행한다.
계속 반복
큐에 실행할 일이 걸리면 실행하게 된다.
실행이 끝나면 다시 렌더링한다.
- 모든 비동기 API들은 작업이 완료되면 콜백 함수를 태스크 큐에 추가한다.
- 이벤트 루프는 ‘현재 실행중인 태스크가 없을 때’(주로 호출 스택이 비워졌을 때) 태스크 큐의 첫 번째 태스크를 꺼내와 실행한다.
각각의 스탭은 병행적으로 일어나지 않고,
하나의 토큰이 계속 1, 2, 3 과정을 돌면서 실행한다.특정 단계에 시간 지연이 있을 경우 다음 단계에 영향을 준다.
- 즉, 우리의 코드가 느리게 되면, 렌더링도 느려지고 큐 체크도 느려진다.
이벤트 루프와 테스크 큐의 관계
- 멀티스레드에서 생산자 <-> 소비자 패턴 (Producer-Consumer패턴)
- 하나의 소비자가 메모리(생산자)에서 읽기만 한다
- 즉, 메모리 동시성 문제는 일어나지 않는다.
- 한명만 소비하는 패턴 = 파이프 패턴
브라우저가 갖고 있는 다른 thread
- network: ajax 요청때 사용
- timer
-setTimeout
,setInterval
- 현재의 크롬은 타이머를 처리하는 별도 스레드를 갖고있다. - message
-window.postmessage
,localstrage
-sessionstorage
간의 메세지 등등
- 브라우저 통신 메세지 - dom event
멀티 스레드 문제도 synchronized문제가 생기기때문에
콜백 큐처럼 guard를 두어서 guard가 처리하게끔 설계함.