FLOW
- 정의 : 컴퓨터가 프로그램을 적재하고 실행시키는 것
- 특징 : 플로우는 실행 중 관여할수 없다.
- 컴퓨터는 프로그램을 끝나기 전까지는 관여할 수 없다.
- 할 수 있는것은 플로우 컨트롤 여기로 비켜라 저기로 비켜라
- BLOCK : 실행이 완료되기전까지 제어권을 넘기지 않는다.
- NON-BLOCK : 제어권이 바로 회복되는 것을 논 블록킹이라고 부른다.
BLOKING
- 플로우는 기본적으로 블로킹이다.
- 모든 흐름제어가 끝나야지 제어권을 반환한다.
- cpu는 그 사이 다른 명령을 내릴 수 없다.
- 자바스크립트에서 큰 json을 파싱을 시키면 화면이 멈친다.
for (const i of (function* () {
let i = 0
while (true) yield i++
})())
console.log(i)
// Process terminated due to long running script
// script timeout
- 이 명령은 무한루프이기 때문에 에러가 발생한다.
- 브라우저가 계속해서 점유하고 있어 플로우를 제거해 버린다.
- 기본적으로 5초 이상으로 제어권을 가지고 있으면 해당 플랫폼이 죽여버린다.
- 현대 os는 이러한 기능을 공통적으로 가지고 있어서 지속적으로 점유를 하고 있으면 프로세스를 죽여버린다.
- 안드로이드 / 아이폰 OS는 통화나 메세지가 우선적으로 처리해야하기 때문에 제어권을 프로그램에게 주어지지 않는다.
BLOCKING FUNCTION
- 일반적으로 블로킹을 애기하는 것은 함수를 기준으로 애기한다(점유하는 시간만큼 블로킹을 일으키는 함수)
const f = (v) => {
let i = 0
while (i++ < v);
return i
}
f(10) // 블로킹 함수
f(10000000000000) // 블로킹 함수
- 시간이 오래걸린다고 블로킹 함수가 아니고, 기본적으로는 모든것은 블로킹 함수이다.
- 블로킹 함수가 지속적으로 브라우저의 제어권을 가지고 있으면 종료가 되기 때문에 제한조건을 생각해야 한다.
- 블로킹 함수 - 제한조건
- 배열 순회, 정렬 - 배열크기에 따라
- DOM 순회 - DOM의 하위구조에 따라
- 이미지 프로세싱 - 이미지 크기에 따라
BLOCKING EVASION(블로킹 피하기)
정의
-
컴퓨터에서 어떠한 작업을 피할때는 Evasion을 사용한다.
-
독점적인 cpu점유로 인해 모든 동작이 정지됨
- 블로킹상태(루프..) 시각적인 데이터가 없으므로 클라이언트는 좋지 못한 ux를 제공
- 고객은 0.1초안에 원하는 상태로 변경되지 못하면 불안함을 느낌.
- sumit 버튼을 수십번 눌러 에러 발생(꼭 막아줘야 한다)
-
타임아웃체크에 의해 프로그램이 강제 중단됨(현대 os / brower 동일)
-
블록킹의 조합을 예측할 수 없음
- 블록 연쇄(함수(함수...)) 작업으로 인해 생긴 블록은 어디서 블록이 생긴지 모른다.
Bloking은 피할 수 없다.
Bloking은 관리해야 할 대상이고 분산 시켜야 할 대상이다.
순차적인 실행
- 3개의 프로그램이 있다면, 첫 프로그램이 실행이 완료되고 다음 프로그램을 실행 시킨다
시분할 운영체제의 동시 실행
- 첫번째 프로그램이 실행 중에 cpu가 제어권을 뺏어 다음 프로그램을 실행시켜 동시에 실행시킨 것처럼 한다.
- Context Switching : 프로그램 실행 중 해당 자원과 코드를 저장해 놓고 다른 프로그램을 실행하는 것
순차적이 시분활 실행보다 빠른데 왜 사용할까?
- 동시작업 선호(네이버 검색하면서, 멜론 음악도 듣고, 카카오톡 채팅도 하고)
- 머신파워의 발전에 따라 컨텍스트 스위치 비용을 신경안써도 된다
- 다중 코어로 하나의 코어에 하나의 프로그램을 실행시켜도 속도의 문제 없음
프로세스와 쓰레드
- 프로세스 : 하나의 프로세스 == 실행 환경
- 쓰레드 : 프로세스 안에서 또 하나의 프로세스를 만든다(또 하나의 시분활 대상)
자바스크립트 thread
- MAIN UI THREAD
- 화면을 그려준다
- 자바스크립트 코드 실행
- BACKGROUD THREAD
- ajax 같은 네트워크 통신(브라우저 별로 백그라운드 쓰레드 숫자는 제한)
- WEB WORKER THEAD
- 자바스크립트로 통제할 수 있는 백그라운드 쓰레드를 만들 수 있다
- 블록킹을 피하는 방법!! 이런 쓰레드로 작업을 나누어준다!!!
Time SLICING
-
정의
- 블록킹의 시간 단위를 줄여 바로 제어권이 반환되게 한다
- requestAnimationFrame을 활용하여 해결한다
- requestAnimationFrame의 매개변수를 화면 갱신 하기 전에 호출
- 프레임 : 브라우저에서 자바스크립트가 실행되는 프로세스의 단위
-
메뉴얼 버전 : 실행 시킬 함수를 판단하여 프레임을 넘겨줄 기준을 조작
const looper = (n, f, slice = 3) => { let limit = 0, i = 0 construnner = (_) => { while (i < n) { if (limit++ < slice) f(i++) else { limit = 0 //계속해서 조건을 초기화 시켜 블로킹의 시간을 제어한다. requestAnimationFrame(runner) break } } } requestAnimationFrame(runner) }
-
자동 버전
- performace.now를 활용하여 계속해서 제한조건을 확인한다(한 프레임당 5초 미만이 제한조건
- performace.now()은 브라우저에서 어플레이케이션이 실행되고 나서 시간을 측정한다.
const looper = (n, f, ms = 5000, i = 0) => {
//한 프레임은 5초 이내로 작동 이상이면 화면 멈춤
let old = performance.now(),
curr
construnner = (_) => {
while (i < n) {
curr = performance.now()
if (curr - old < ms) f(i++)
else {
old = curr //계속해서 조건을 초기화 시켜 블로킹의 시간을 제어한다.
requestAnimationFrame(runner)
break
}
}
}
requestAnimationFrame(runner)
}
WEB WORKER
-
자바스크립트를 실행하는 메인 쓰레드 UI쓰레드인데, 별도의 쓰레드를 만들수 있다(멀티 쓰레드!!!)
-
작동방식은 멀티쓰레드 패턴의 워커 쓰레드를 따르고 있다.
-
Web Worker에는 캔버스 객체, ajax 객체가 있다
-
Web Worker가 블록이 걸려도 메인 UI는 영향을 주지 않는다.
-
원시값만 갈 수 있다. 객체가 간다면 메인 쓰레드에서도 접근 할 수 있기 때문이다.
-
별도의 js 파일로 존재해야 한다.
-
Atomics 객체를 이용하여 객체를 전달 할 수 있다.(진행 중인 쓰레드가 완료되기 전까지 다른 접근 불가)
const backRun = (f, end, ...arg) => { // 별도의 js파일이 존재해야 하지만 바이너리 파일로 변환하여 전송시켜준다. const blob = new Blob([`onmessage =e=>postMessage((${f})(e.data));`], { type: 'text/javascript', }) const url = URL.createObjectURL(blob) const worker = new Worker(url) worker.onmessage = (e) => end(e.data) worker.onerror = (e) => end(null) worker.postMessage(arg) } backRun((v) => v[0] + v[1], console.log, 3, 5)
정리
- 블로킹을 피하는 방법은 논 블로킹이다(서브루틴이 즉시 플로우 제어권을 내놓는것)
- 순차에 무관한 더욱 더 안정적인 알고리즘을 짠다(병행성 프로그램...)
SYNC ASYNC
정의
-
Block/NoNBlock의 주요 관점은 제어권을 바로 받을 수 있냐?
-
SYNC : 서브루틴이 즉시 값을 반환
const double = (v) => v * 2 console.log(double(2)) //4
-
ASYNC : 서브루틴이 콜백을 통해 값을 반환
const double = (v, f) => f(v * 2) double(2, console.log) //4
SYNC
-
BLOCK (nomalAPI, legacyAPI)
const sum = (n) => { let sum = 0 for (let i = 1; i <= n; i++) sum += i return sum } sum(100)
-
NON BLOCK(old API ⇒ IOCP, Future, img.complete..)
- 블록킹이 될 가능성이 높다!!!(사용하지 말자.. 초급개발자는 오류를 발생률이 높다? )
- 서스펜션 패턴 : 두개의 쓰레드가 한쪽은 생산하고 한쪽은 감시하는 것
const sum = n= >{ const result = {isComplete:false}; requestAnimationFrame(_=>{ let sum = 0; for(let i = 1; i <= n; i++) sum += i; result.isComplete = true; result.value = sum; }); return result; }; const result = sum(100); while(!result.isComplete); //여기서 계속 멈춤 error console.log(result.value);
ASYNC
-
BLOCK(함정 ⇒ 무조건 피해야한다)
const sum = (n, f) => { let sum = 0 for (let i = 1; i <= n; i++) sum += i return f(sum) } sum(10, console.log) console.log(123) //55 → 123
-
NON BLOCK(modern API)
- 콜백으로 짜는 이유???
- 값으로 받으면 그 값에 대한 처리를 해주는 코드를 써야되고, 그 값을 다시 이용하려면 중복 발생
- 콜백은 하나의 함수안에 값을 처리할 함수를 캡슐화해서 몇번이나 재사용 가능
- 소비하는 측의 로직을 관리하기 위해 캡슐화를 시켜놓은게 콜백이다!!!
const sum = (n, f) => { requestAnimationFrame((_) => { let sum = 0 for (let i = 1; i <= n; i++) sum += i f(sum) }) } sum(10, console.log) console.log(123) //123 → 5
- 콜백으로 짜는 이유???
SIMILAR ASYNC-BLOCK
-
미루기 패턴 (다음 프레임으로 미룬다) - 안티 패턴
const sum = (n, f) => { let sum = 0 for (let i = 1; i <= n; i++) sum += i return f(sum) } sum(1000000, console.log) console.log(123) //55 → 123
-
백그라운드로 어마어마한 쓰레드를 보내면 쓰레드 고갈로 죽는다 - 안티패턴
const backRun = (f, end, ...arg) => { const blob = new Blob([`onmessage =e=>postMessage((${f})(e.data));`], { type: 'text/javascript', }) const url = URL.createObjectURL(blob) const worker = new Worker(url) worker.onmessage = (e) => end(e.data) worker.onerror = (e) => end(null) worker.postMessage(arg) } const f = (v) => { for (let i = 1, sum = 0; i <= v[0]; i++) { sum += i } return sum } leti = 1000 while (i--) backRun(f, console.log, 100000)