9. 고 블록
고 블록
순차적인 코드를 사건 중심 코드로 재작성하는 것
제어의 역전을 통해 실행하던 스레드가 블로킹되는 대신 “주차 상태”로 멈추고,
다른 처리를 할 수 있게 해준다.
(스레드와 달리) 사용하는데 많은 비용이 들지 않는다.
제어의 역전 과정
1) 고 블록 내부에서 작성된 코드는 하나의 State Machine으로 전환
2) 채널에 Read/Write시 (블로킹 대신)갖고 있던 스레드의 통제를 포기하고 구석에 주차(parking)
3) 다음 실행 순서가 돌아오면 상태를 전이시킨다.
4) 원래 하던 일을 다른 스레드에서 계속 수행한다.
10. 고 블록
2. x, y 값을 입력한 후...
3. 결과값이 출력되었다.
1. 고 블록을 사용하지 않을 경우
x, y 값을 입력 받을 때까지 블로킹 된다.
11. 고 블록
고 블록을 사용하여 블로킹이 발생하지 않았다.
이때 고 블록 구문에는 <!!, >!! 대신 <!, >!을 사용하였다.
15. 여러 채널 다루기
alt! 함수
둘 이상의 채널 중 하나를 선택하여 값을 읽거나 쓰게 해준다.
코드를 효율적이며 간결하게 만들어 준다.
1. 2개의 채널을 만들고,
2. go 블록 무한 루프를 돌며 alt!를 이용해 두 채널에서 값을 읽는다.
16. 여러 채널 다루기
timeout 함수
명시한 밀리초만큼 흐르면 자동으로 닫히는 채널을 리턴
Reified Timeout (구체화 타임아웃)
여러 개의 연결을 하나로 묶어서 전체적으로 소비하는 시간에 대해 제한을 줄 때 유용하다.
한 개의 타임아웃을 만든 후, 열에 담긴 각각의 연결마다 그 타임아웃을 전달
17. 여러 채널 다루기
구체화 타임아웃 : 에라토스테네스의 체 코드 수정
무한 루프를 돌며 alt!!에 의해
(1) 새로운 소수가 준비되거나
(2) limit가 타임아웃이 될때까지 블로킹된다.
18. 비동기적인 폴링
폴링 함수
정기적으로 수행될 action이 go 블록 내부에서 호출되어
“주차하는 함수(<!)”를 호출할 수 있을것 같다.
예상과 달리 에러가 발생하였다.
“주차하는 호출”은 고 블록 내에서 “직접적”으로 일어나야 한다.
19. 비동기적인 폴링
폴링 매크로
<함수> 대신 <매크로>를 사용하여 앞서 보았던 “폴링 함수”의 문제점 해결
<매크로>는 직접 컴파일되는 것이 아니라 컴파일될 코드를 리턴한다.
즉, 컴파일 시 확장되므로 전달된 코드는 inline 처리되어 poll의 go 블록 내에 직접 포함된다.
매크로 확장(macroexpand)를 통해 생성된 코드 확인 가능
20. 비동기적인 폴링
폴링 매크로
매크로 확장 (macroexpand)
전달된 코드가 매크로 자체 내부에 있는 코드로 어떻게 이어졌는지(Spliced),
seconds#가 어떻게 고유한 이름으로 전환되었는지 알 수 있다.
21. 비 동기적인 IO
비 동기적 IO
연결마다 하나의 스레드를 갖는 것이 아닌,
여러 동작을 한꺼번에 시작한 다음 어느 것이 데이터가 준비되었을 때 통보해오는 방법
콜백 호출이 많아져 문제가 발생할 수 있다.
core.async로 통합하여 구현할 예정
27. 클로저 스크립트
클로저 스크립트
https://github.com/clojure/clojurescript
“자바 바이트코드”가 아닌 “자바스크립트”로 컴파일되는 클로저 버전
서버 / 클라이언트가 “클로저”로 작성된 웹 어플리케이션 작성 가능
클로저의 core.async 지원
콜백 지옥 해결 가능
클로저 스크립트의 컴파일 과정
클라이언트 측 : 클로저 스크립트를 자바스크립트 파일로 컴파일
서버 측 : 서버측 코드 컴파일 후 자바스크립트를 포함한 전체를 서비스하기 위한 서버를 실행
28. 클로저 스크립트
기존 자바스크립트
자바스크립트 엔진은 “단일 스레드” 사용
멀티 스레드와 관련있는 core.async와의 연관관계는?
Cooperative Multitasking (협동적인 멀티태스킹)
go 매크로 사용
실제로는 “단일 스레드”를 사용하지만 “여러 개의 스레드”를 사용하는 것 처럼 보이게 구현
29. 기본 예제
기본 예제
입력 받은 2개의 메시지를 각각 1초, 1.5초 간격으로 화면에 출력
클라이언트 측 소스 코드
31. 기본 예제
실행 방법
core.cljs 가 있는 폴더로 이동
컴파일 : lein cljsbuild once ⇒ target 폴더 생성
서버 실행 : lein run
웹 브라우저로 접속
32. 추가 예제
추가 예제
마우스 클릭 시 이벤트 처리
클릭하면 크기가 줄어들다가 화면에서 사라지게 되는 원을 보여주는 웹 페이지
콜백 중심의 Javascript를 core.async의 채널 중심으로 옮김으로써 “콜백 지옥”에서 탈출할 수 있다.
클라이언트 측 소스 코드
37. 출처
7가지 동시성 모델 (한빛미디어, 폴 부처 지음 / 임백준 옮김)
Clojure Documentation : https://clojuredocs.org/core-library
에라토스테네스의 체 Wikipedia : https://ko.wikipedia.org/wiki/에라토스테네스의_체
Editor's Notes
remove< 함수는 불리언 함수의 결과가 false에 해당하는 값만 적혀있는 채널을 리턴한다.
역따옴포(`) : 문법 인용 연산자. 소스 코드를 받아 실행하는 대신, 나중에 컴파일될 수 있는 표현을 리턴
~(unquote)연산자, ~@(unquote splice)연산자 : 코드 내에서 매크로에 전달된 인수를 참조
#(auto-gensym) 접미사 : 클로저가 고유한 이름을 생성하도록 보장
4번째 줄에 생성된 자바스크립트 코드는 7번째 줄의 <div id=”content”></div>에 내용을 채운다.
:require-macros 를 통해 매크로 참조 : 클로저와 클로저 스크립트 간의 차이점
6줄 output 함수 : 메시지를 DOM 요소에 더하기 위해 “구글 클로저 라이브러리” 사용
14줄, 18줄 output 함수 사용 : 각 go 블록 내에서 1초, 1.5초 마다 메시지 출력
20줄 : 실행
구글 클로저의 그래픽 지원 도구 이용
10번째 줄 : create-graphics 함수는 DOM 요소를 받아들여서 그래픽 표면처럼 사용할 수 있는 객체를 리턴
15번째 줄 : 원의 선 색 지정
19번째 줄 : 구글 클로저의 drawCircle 함수로 원을 그린다
21번째 줄 : 25밀리초의 타임아웃 값을 사용하는 루프에 들어가서
22번째 줄 : setRadius 함수를 초당 40번씩 호출
25번째 줄 : 반지름이 0이 되면 dispose 함수를 호출하여 원을 제거
31번째 줄 : 마우스 클릭 이벤트를 받을 수 있도록 구글 클로저의 (이벤트 리스너를 등록하게 하는) listen 함수를 사용