클로저 core.async (feat. golang)

Heehong Moon
bgpworks
Published in
4 min readSep 19, 2017

golang으로 개발하면 생산성도 높은 편이고 share library(.so, .dll)를 사용하지 않는 실행파일 하나로 빌드가 된다는게 매력적이다. golang을 메인 언어로 선택하는 여러가지 이유가 있겠지만 개인적으로 go routinechannel을 사용할 수 있다는게 가장 큰 이유이다.

go routine & channel

보통 async 작업이 복잡한 경우 코드가 엄청 복잡해져서 알아볼수 없게 되는데, nodejs 플랫폼에서 조그만 웹서버를 구현해 보면 누구나 겪는 현상이다. 왜냐면 nodejs는 기본 철학 자체가 non-blocking이고 모든 함수가 기본적으로 callback을 받는 async함수이기 때문이다.

이런 문제로 javascript쪽에서는 promise등 개념이 나오고 callback hell을 어느정도 막아주긴 했지만 코드 가독성이 높아졌는지는 의문이라 별로 좋아하진 않는다. ES7에 async/await는 가독성이 꽤 좋아보이는데 개인적으로 아직 써보진 않았다. 어쨋건 go routine은 callback hell을 없애는 async/await 처럼 아예 언어에 포함되어 async 구현을 심플하게 할 수 있게 도와주는 개념이다.

go routine은 green thread(light weight thread)에서 실행하는 thread이고, 마치 우리가 보통 언어에서 사용하는 OS의 Thread와 기본 개념자체는 동일하다. OS thread처럼 go routine 안에 있는 코드들은 동시에 실행가능한데 차이가 있다면 엄청 가벼운 thread라 동시에 수십만개 또는 수백만개를 켤수도 있다.

channel은 여러 go routine이 동시에 실행되는데 그 사이 통신을 하는 툴이라고 생각하면 된다. channel은 쉽게 생각하면 그냥 어떤 메세지를 전달하는 queue처럼 생각하면 되는데, 대신 중간 buffer가 없어서 값을 빼려고 하면 blocking이 되고 누군가가 해당 channel에 값을 넣어야 리턴되면서 쭉 실행된다.

go routine과 channel을 활용하면 async로 꽤 복잡한 처리를 간단하게 만들수 있는데, 개인적으로 제일 인상 깊었던 예제는 Fake Google Search이다.

구글처럼 키워드를 검색하면 Web, Image, Video 검색서버에 쿼리 하는데, 각각의 검색 서버는 replica서버가 여러대 있다. 동시에 모든 서버에 쿼리를 하되, replica서버 중 가장 빠른 결과를 리턴하고 세가지 종류 모두 리턴한다. 그리고 80ms이 지나도록 리턴하지 않는 검색결과는 무시한다.

이걸 말로 설명하기도 힘든데, 어쨋건 go routine & channel로 구현하면 다음처럼 아름답게 구현된다.

위 샘플이 소개된 Google IO 2012영상인데, golang으로 async 관련된 작업을 할때 얼마나 편해지는 쉽게 설명한다.

core.async

go routine이 마음에 들어서 golang을 선택할 수도 있겠지만 현실적으로 불가능한 경우도 있다. 예를들면 JVM, nodejs 플랫폼에서 작업을 해야 하는 경우이다. 이런 경우 go routine때문에 기존 코드를 다 포팅할 수는 없다.

Clojure는 JVM, nodejs에서 실행가능 하며, go routine & channel을 그대로 구현한 library가 core.async 이다. go routine은 언어 디자인 자체에 포함되어야 하고, 일반적인 언어에서는 구현조차 불가능하다. 그런데 clojure는 lisp이기 때문에 하나의 library형태로 go routine이 구현되었다.

core.async에는 심지어 go routine 이름도 “go”로 되어 있어서 golang에서 코딩하는것과 거의 동일하게 사용가능하다. 위의 Fake Google Sample을 누가 clojure core.async로 구현한건 다음과 같다.

clojure는 type을 따로 쓰지 않기 때문에 golang 버전보다 훨씬 간결해 보인다. 그리고 clojure의 core.async는 go routine말고 일반 thread와 통신할 수 있는 channel도 구현되어 있어서 기존 코드에 go routine기반을 끼워넣기 쉽게 되어 있다.

core.async는 ClojureScript에서도 사용 가능하기 때문에 웹프론트에서 복잡한 ajax 콜을 해야 하는 경우 cljs+core.async 조합으로 사용하면 꽤 좋을듯하다.

--

--