[Go] 고루틴과 채널, 동기화
고루틴의 대략적인 형태와 사용법 등을 다뤄보겠다.
고루틴이 뭔가?
일종의 스레드라고 봐도 된다.
정확히는 경량 스레드이고, Go 자체 스케줄러에 의해 효율적으로 관리된다.
때문에 네이티브 스레드에 비해서 사용하는데 부담도 없고, 최적화도 잘 먹히는 편이다.
참조
https://blog.naver.com/sssang97/221717390326
Go에서 가장 강력한 기능이라고 단언할 수 있다.
고루틴의 사용법
고루틴은 "go"라는 키워드를 통해 동작한다.
함수 호출 앞에 go만 붙이면 그냥 함수 실행이 아니라 고루틴 실행이 돼서 비동기적으로 실행이 된다.

근데 실행결과가 뭔가 이상하다.
스레드와 유사한 비동기 태스크이기 때문에 발생하는 문제다.
고루틴은 다음 코드라인까지 완료를 기다리지 않고 병행적으로 실행된다.
때문에 고루틴이 제대로 시작되기도 전에 main 함수가 끝나버린 것이다...
저걸 제대로 실행되게 하려면, 여라가지 방법이 있지만 가장 간단한 방법은 무한루프를 띄우는 것일 테다.

그럼 당장은 실행이 된다.
하지만 여기에는 문제가 많다. 프로그램이 끝나지 않는다는 것이다.
게다가 main task와 고루틴 task가 뭔가 서로 상호작용을 한다거나 할때는 어떻게 해야할까?
보통 Go에서는 채널 등을 활용해서 비동기 프로세스들을 동기화하고 합을 맞춘다.
고루틴과 채널
채널은 Erlang에서 시작된 동기화 기법 중 하나인데, 일종의 큐를 만들어서 스레드가 큐를 통해 값을 주고받을 수 있게 하는 것이다.
성능 면에서의 최선은 아니지만, 굉장히 편리하고 안정적으로 동기화를 이룩할 수 있다는 장점이 있다.
채널은 make와 chan 키워드를 통해 생성할 수 있고, 그 내부 값에 대해서는 타입을 지정해서 특수화할 수 있다.
그리고 "채널 <- 값"의 형태로 송신할 수 있고, "<- 채널"의 형태로 값을 수신받을 수 있다.
채널이 값을 수신받으면 값이 들어올때까지 블럭이 된다는 점을 응용해서, 아래와 같이 동기화를 구현할 수 있다.
int 타입은 장식이고, 채널은 그냥 완료 여부만 체크하는 단순한 케이스로 활용했다.

그럼 잘 실행되었을 것이다.
당연하지만, 채널을 통해 고루틴에서 처리한 결과를 다른 태스크에 전달할 수도 있다.
이를 잘 응용하면 타 언어들의 async/await과 비슷한 루틴을 구성할 수 있다.
아래는 단순한 덧셈 함수를 고루틴으로 구현한 것이다.
실용성이 있는 예제는 아니지만, 그 맥락을 파악하기에는 적절하다고 본다.


이외에도 Go는 waitgroup, mutex 등 다양한 도구들을 사용해서 동시성을 제어할 수 있는 수단을 제공한다.
그건 차근차근 별도로 다뤄보도록 하겠다.