코드스피치 강의 ES6+ 5회차 정리

August 23, 2020

FLOW

  1. 정의 : 컴퓨터가 프로그램을 적재하고 실행시키는 것
  2. 특징 : 플로우는 실행 중 관여할수 없다.
    • 컴퓨터는 프로그램을 끝나기 전까지는 관여할 수 없다.
    • 할 수 있는것은 플로우 컨트롤 여기로 비켜라 저기로 비켜라
    • 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

  1. MAIN UI THREAD
    • 화면을 그려준다
    • 자바스크립트 코드 실행
  2. BACKGROUD THREAD
    • ajax 같은 네트워크 통신(브라우저 별로 백그라운드 쓰레드 숫자는 제한)
  3. WEB WORKER THEAD
    • 자바스크립트로 통제할 수 있는 백그라운드 쓰레드를 만들 수 있다
  4. 블록킹을 피하는 방법!! 이런 쓰레드로 작업을 나누어준다!!!

Time SLICING

  1. 정의

    • 블록킹의 시간 단위를 줄여 바로 제어권이 반환되게 한다
    • requestAnimationFrame을 활용하여 해결한다
    • requestAnimationFrame의 매개변수를 화면 갱신 하기 전에 호출
    • 프레임 : 브라우저에서 자바스크립트가 실행되는 프로세스의 단위
  2. 메뉴얼 버전 : 실행 시킬 함수를 판단하여 프레임을 넘겨줄 기준을 조작

    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)
    }
  3. 자동 버전

    • 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)

© 2023, Customized by Joon