2020-02-17 TIL

할 일 목록

  • 코루틴 정리.
  • 리액티브, 펑터 모나드 정리.
  • http 3장 까지 코드로 해볼 수 있는것 다 해보기.
  • 책 모임.

완료하지 못한 목록

  • http 3장 까지 코드로 해볼 수 있는것 다 해보기.

완료 목록

  • 코루틴 정리.
  • 책 모임.

5Fs

1. Fact

1. 코루틴

  • 우리가 비동기 non-blocking으로 짜지 못하는 가장 큰 이유는 예측이 불가능하기 때문이다.
  • 일반적으로 우리가 사용하는 sync-blocking(싱글 스레드 콜백) 방법 밑의 코드와 같이 함수를 선언하고, main 에서 함수를 사용하는 경우는 함수가 어디서 반환될지 우리는 예측이 가능하다.
fun runFunc() {
    println("함수 실행")
}

fun main() {
    println("메인을 실행한다.")
    runFunc()
    println("메인을 종료한다.")
}
  • 하지만 콜백으로 짠다면 동작을 예측을 할수가 없다. 밑의 코드를 보면 현재 object의 속성 count를 1씩 증가하는 코드를 작성하고 있다. 하지만 count가 2가 되는 시점에 async-nonblocking 함수(스레드를 새로 생성하여 메인 스레드를 멈추지 않고 1초 홀딩 후에 직접 2를 넣어주는 함수)로 직접 2를 넣어주었다. 우리가 기대한 결과값은 1,2,3,4 순서대로 나오는 것을 기대했지만, 1,2,3,2라는 결과값을 받았다. 멀티스레드 콜백(비동기 논블로킹) 방식은 예측하기가 힘들어진다. 그러다 보니 우리는 위와같이 싱글스레드 콜백 방식으로 코드를 작성한다.
const object = {count:0};
const async_nonblocking_fun = (callback) => {
    setTimeout(callback ,1000)
}
const addCount = (object) => {
    object['count'] = object['count'] + 1;
    console.log(object['count']);
}
const inputTwo = () => {
    object['count'] = 2;
    console.log(object['count']);
}

addCount(object);
async_nonblocking_fun(inputTwo,object);
addCount(object);
addCount(object);
  • 그래서 자바의 future는 async blocking 방식이다. 자바의 future을 사용할 경우, 멀티 스레드를 생성하여 완료되면 callback을 호출하지만, 실제로 제어권이 main으로 넘어오지 않고, blocking을 하게된다. 그러면 사실상 싱글스레드를 사용하는 것과 마찬가지이다..
  • 위의 문제점을 해결하기 위하여 콜백이 호출되는 시점을 우리가 원하는 시점에 제어하는 방법을 사용한다.

    1. 로딩이 끝난 상태와 끝나지 않은 상태로 구분할 수 있다.
    2. 로딩이 끝난 상태에서 실행하면 바로 호출이 될것이고
    3. 로딩이 끝나지 않은 상태라면, callback 처럼 대기해서 완료되면 실행이 되도록 한다.
    4. 그렇게 되면 async-nonblocking 코드를 sync-blocking 코드 처럼 우리가 보기 편하게 작성할 수 있다.
  • 위의 한가지 예는 completableFuture이다. 자바스크립트에선 promise와 동일하다고 생각하면 된다.

    1. 한 가지 예를 들어보자. 공장에서 자동차를 조립하는데 타이어, 프레임, 휠, 운전대, 라이트, 엔진, 등을 모두 제조해서 조립을 한다고 생각해보자.
    2. 그렇게 되면 차동차의 조립이 모두 성공하기 위해서는 각각의 부품들이 각 라인에서 생산되어 모두 나와야 완성된 자동차를 만들수가 있다.
    3. 여기서 각각 부품들은 각각의 다른 스레드에서 생성하고, 모두 완성 되면 자동차를 조립하는 코드를 작성해보자.
  • promise가 강력한 이유

    • 만약에 result는 비동기 논블로킹으로 요청을 하고, 밑에 코드를 동기적으로 작성할 수 있다. 그리고 나중에 result가 필요할 때 callback을 호출하게 하여 동작이 가능하다.(callback의 호출 시점을 제어할 수 있기 때문에 )
const engineLine = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("engine finish")
        resolve("engine")},1000);
})
const frameLine = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("frame finish")
        resolve("frame")},1000);
})
const wheelLine = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("wheel finish")
        resolve("wheel")},1000);
})
const tireLine = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("tire finish")
        resolve("tire")},1000);
})
const finishLine = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log("finish")
        resolve("tire")},1000);
})

engineLine.then(engineLine)
.then(frameLine)
.then(wheelLine)
.then(tireLine)
.then(finishLine);
  • 멀티 스레드 패턴

    • IOC
    • background 입력 스레드가 항상 버퍼를 갱신하고 다른 멀티스레드는 버퍼를 감시한다.
    • suspended pattern이며 읽고 쓸때 syncronize를 할 필요가 없기 때문에 굉장히 빠르다.
  • 컴퓨터는 사실 비동기가 없다. 우리는 노이만 머신을 사용하기 때문에 한번에 명령이 적재되면 명령을 중간에 멈출 수 있는 방법이 없다. 무조건 모두 실행되야 하고 무조건 블로킹 당한다. 그러기 때문에 우리가 알고있는 비동기는 멀티스레드로 만든것이다. 멀티스레드는 왜 비동기가 될까? 명령을 멈출 수 있기 때문이다. 원래 노이만 머신은 메모리에 적재된 명령을 한번에 소진해야 되는데 스레드를 사용하면 1번 스레드가 자기에 적재된 명령을 실행하다 끊고 다른 스레드로 넘어가서 코드를 실행한다. 실질적인 시분할이 일어난다. 따라서 동기적인 명령을 멈출 수 있는 유일한 방법은 프로세스나 스레드밖에 없다. OS 차원에서 그외에 우린 동기적 명령을 멈출 수 있는 방법은 없다.
  • 그럼 언어에서는 가능할까? for문 돌때 break 같은 전용 flow 명령을 쓰지 않고, 3번 돌다가 멈췄다가 4번 돌다가 이렇게 하는 방법은 없다. 스레드만 os차원에서만 가능하다.
  • 그럼 언어 차원에서 그것을 흉내내기 위해 만든 문법이 yield 중간에 빠졌다가 들어가는데,

2. 코루틴

리스코프 치환원칙 공부하기

  • 코틀린 컬렉션은 왜 자바의 컬렉션이 있는데도 불구하고 새로 짰을까 ?

    • mutable이 mutable 아닌것에 의존하고 있다는게 불안정함 형변환이 되기 때문에 우리는 lsp 계층에 의해서 뮤터블 셋이 그냥 셋으로 부모로 대체할 수 있다. 객체지향의 대체가능성은 자식은 부모로 대체할 수 있다. 여기서 보면 mutableList는 List를 대체하게 되니까 언제나 list처럼 쓸 수 있다는 이야기다. 그래서 항상 이 코틀린의 현재 계층구조에서는 굉장히 불안정하다. list 는 mutable로 mutable은 list로 언제나 타입 캐스팅이 가능함. 걔다가 얘낸 다 인터페이스다 스테레오 타입으로 되어있는 그래서 얘는 구현체 조차도 아님 실제 구현체는 따로 있다는 이야기다. 실제 구현체가 mutable interface를 상속 받았다는 이야기는 list interface를 상속 받았다는 이야기이도 하다. list나 mutableList는 둘다 서로를 타입캐스팅할 수 있음. mutable list를 list로 타입 캐스팅 가능. 여기선 list를 구현한 구상 객체가 보이지 않음. list만 구현한 구상객체조차도 mutablelist로 타입 캐스팅이 된다. 구현체가 list를 구현했을때 mutable list는 구현하지 않도록 해야하는데 실제 현재 코틀린 구현체는 mutable list가 list까지 구현하는 구현체를 가진다. 254 페이지는 클래스 다이어그램이 아니다. 좋은 계층 구조는 인터페이스만으로 되있지 않다. 타입을 확립시킬때는 구상클래스가 개입하게 되있다.OL을 방지하기 위해서 OL이란
    • 여기 더 좋은 그림은 리스트를 list를 mutable 리스트로 화살표가 가는데 이렇게가 아니라 abstract list라는 클래스가 list 인터페이스를 가르키고있는 별도의 박스가 있는 것임. 그럼 mutable list로 내려갈 수 없음. mutablelist 밑에도 absctact mutable list라는 클래스가 따로있는게 나을 수도 있다. 이런 경우엔
  • 근데 왜 이런 위험을 감수하고 왜 만들었을까 ?

    • 가장 중요한 이유는 mutable, imutable 지원
    • 자바 컬렉션의 가장큰 문제를 mutable, immutable로 보는 것이다. 28.31 까지 들었음.

HTTP

  1. 메시지 구성요소

    • request

      1. request line

        • 메소드, URI, HTTP 버전
      2. http 헤더 필드 : 클라이언트와 서버간의 통신에서 요청 응답 모두에 사용되고 있고, 부가적으로 중요한 정보를 전달하는 역할을 담당. 메시지 바디의 크기나 사용하고 있는 언어, 인증 정보 등을 브라우저나 서버에 제공하기 위해 사용되고 있다.

        • 헤더 필드의 구조는 ‘헤더 필드명 : 필드 값’ 으로 들어감. Content-Type:text/html 처럼
        • 한개의 HTTP 헤더필드가 여러개의 필드값을 가질 수 있다.
        • 리퀘스트 헤더 필드 : 클라이언트 측에서 서버측으로 송신된 리퀘스트 메시지에 사용되는 헤더로 리퀘스트의 부가적 정보와 클라이언트의 정보, 리스폰스의 콘텐츠에 관한 우선순위 등을 부가한다.
        • 일반 헤더 필드 : 리퀘스트 메시지와 리스폰스 메시지 둘다 사용되는 헤더이다.

          1. Cache-Control : 디렉티브로 불리는 명령을 사용하여 캐싱 동작을 지정함. 여러개의 디렉티브를 지정할 경우 콤마를 사용함. 리퀘스트 및 리스폰스 할 때에 사용가능

            • 캐시가 가능한지 여부를 나타내는 디렉티브

              1. public : 다른 유저에게도 돌려줄 수 있는 캐시를 해도 좋다는 것을 명시적으로 나타냄
              2. private : 리스폰스는 특정 유저만을 대상으로 하고 있음을 나타냄.
              3. no-cache : 리퀘스트는 캐시된 리스폰스를 받지 않는다는 것을 의미하며 중간의 캐시서버는 오리진 서버까지 리퀘스트를 전송해야함. 리스폰스에 사용된 경우엔 캐시서버는 리소스를 저장할 수 없음. 또 no-cache=Location이 지정된 경우, 지정된 헤더 필드만 캐시할 수 없음.
            • 캐시로 보존 가능한 것을 제어하는 디렉티브

              1. no-store : 리퀘스트(그와 대응되는 리스폰스) 혹은 리스폰스에 기밀 정보가 포함되있음을 나타냄. 그래서 일부를 로컬 스토리지에 저장 안되도록함.
            • 캐시 기한이나 검증을 지정하는 디렉티브

              1. s-maxage : max-age와 똑같지만 다른점은 여러 유저가 이용할 수 있는 공유 캐시 서버에만 적용됨.
              2. max-age : 리퀘스트에서 사용된다면 지정된 값보다 새로운 경우엔 캐시되었던 리소스를 받아들일 수 없음. 리스폰스에서 사용됬다면 캐시 서버가 유효성의 재확인을 하지 않고 리소스를 캐시에 보존해 두는 최대시간을 나타냄.
              3. min-fresh
              4. max-stale
              5. only-if-cached
              6. must-revalidate
              7. proxy-revalidate
              8. no-transform
            • Cache-Control 확장

              1. cache-extension 토큰
              2. Connection
              3. 프록시에 더이상 전송하지 않는 헤더 필드를 지정 : 리퀘스트 혹은 리스폰스에서 Connection 헤더 필드를 사용하며 프록시 서버에 더 이상 전송하지 않는 헤더(hop by hop헤더)를 지정할 수 있다.
          2. Connection

            • 역할

              1. 프록시에 더이상 전송하지 않는 헤더 필드를 지정
              2. 지속적 접속 관리
            • 사용방법 Connection: 더이상 전송하지 않는 헤더 필드명
            • Connection:Close : 서버측에서 명시적으로 끊고 싶을때 사용.
            • Connection:Keep-Alive : HTTP/1.1 이전 버전에선 keep-alive가 기본이 아니었기 때문에, 오래된 버전의 http에서 지속적 접속을 할 경우 사용.
          3. date

            • HTTP 메시지를 생성한 날짜를 나타냄.
          4. Pragma

            • HTTP1.1보다 오래된 버전 또는 HTTP/1.0와의 후방 호환성만을 위해 정의되 있는 헤더필드다.
            • no-cache 하나만 지정할 수 있고, 리퀘스트에만 지정 가능. 중간 서버의 http 버전을 모르기 때문에 Cache-Control : no-cache와 pragma:no-cache를 같이 보낸다.
          5. Trailer

            • 메시지 바디 뒤에 기술되 있는 헤더 필드를 미리 전달할 수 있음. HTTP/1.1에 구현되있는 청크 전송 인코딩을 사용하고 있는 경우에 사용가능
          6. Transfer-Encoding

            • 메시지 바디의 전송 코딩 형식을 지정하는 경우에 사용됨.
          7. Upgrade

            • HTTP 및 다른 프로토콜의 새로운 버전이 통신에 이용되는 경우에 사용됨.
            • Upgrade 헤더 필드에 의해서 업그레이드 되는 대상은 클라이언트와 인접한 서버 사이뿐이기 때문에 Upgrade 헤더 필드를 사용하는 경우는 Connection:Upgrade도 지정할 필요가 있다.
          8. via

            • 클라이언트와 서버 간의 리퀘스트 혹은 리스폰스 메시지의 경로를 알기 위해 사용됨.
            • 프록시 또는 게이트웨이는 자신의 서버 정보를 via 헤더 필드에 추가한 뒤에 메시지를 전송한다.
            • via 헤더 필드는 전송된 메시지의 추적과 리퀘스트 루프의 회피 등에 사용되기 때문에 프록시를 경유하는 경우 반드시 부가해야함.
          9. warning

            • 기본적으로 cache에 관한 문제의 경고를 유저에 전달함.
        • 리퀘스트 헤더 필드 : 클라이언트 측에서 서버 측으로 송신된 리퀘스트 메시지에 사용되는 헤더로 리퀘스트의 부가적 정보와 클라이언트의 정보, 리스폰스의 컨텐츠에 관한 우선 순위 등을 부가합니다.
        • 엔티티 헤더 필드 : 리퀘스트 메시지와 리스폰스 메시지에 포함된 엔티티에 사용되는 헤더로 콘텐츠 갱신 기간 등의 엔티티에 관한 정보를 부가한다.
      3. 그외

        • 쿠키, set-Cookie, Content-Deisposition 같이 외에 더 있음.
        • End-to-end 헤더 : 이 헤더는 리퀘스트나 리스폰스의 최종 수신자에게 전송됨. 캐시에 구축된 리스폰스 중 보존되야 하고, 다시 전송되지 않으면 안되도록 되어 있음.
        • Hop-by-hop 헤더 : 한 번 전송에 대해서만 유효하고 캐시와 프록시에 의해 전송되지 않는것도 있음.
    • response

      1. status line

        • HTTP 버전, 상태코드, 설명
      2. HTTP 헤더 필드

        • 리스폰스 헤더 필드 : 서버에서 클라이언트로 송신한 리스폰스 메시지에 사용되는 헤더로 리스폰스의 정보, 서버의 정보, 클라이언트의 추가 정보 요구등을 부가한다.
        • 일반 헤더 필드
        • 엔티티 헤더 필드
      3. 그외

2.Feelings

  • 책만 읽는게 아니라 코드로 쳐보면서 공부를 하다 보니 더 깊게 공부를 할 수 있는것 같다.
  • 물리적 시간이 절대적으로 부족하다.. 코틀린 공부할 시간도 부족하고, http 책읽는 시간도.. 직접 만들어보는 시간도 다 부족하다.
  • 시간이 너무 부족하다 .. 공부할 시간이 부족하다.

3.Findings

  • 평소에 너무 자주 기억해내려고 집착하지 말고, 내가 만들어놓은 패턴을 이용하여 적당한 망각을 이용하여 한다면, 더 효율적일 것이다.
  • 비동기 논블로킹의 문제로 콜백이 언제 호출되는지 예측이 불가능 한데, 우리는 반제어를 할 수 있는 프로미스나 completablefuture를 사용한다. 이것을 사용한다면, 콜백이 호출되는 시점을 우리가 제어할 수 있다.
  • 코틀린을 공부한다면 작은 코드를 직접 짜보고 하는 시간이 절대적으로 필요하다는 것을 알게되었다.

4.Future Action Plan

  • 내일은 반드시 리액티브 코틀린과 코틀린 데이터 컨테이너 펑터 모나드 어플리커티브 부분을 다시 복습한다.
  • 모두 끝내고, 코틀린 이번주 내용을 공부한다.

5.FeedBack


Written by@Zero1
This blog is for that I organize what I study and my thinking, feeling and experience.

GitHub