Useful GO coding pattern
프로그래밍 언어 GO 작성 시 유용한 패턴에 대해 공유한다.
1. Broadcasting with observer pattern
3. Superloop considering cleanup
4. Synchronization
- c.incomingMsgChan 으로 모든 채널의 메세지가 들어올 때, range와 case를 사용하여 선택적으로 listening함으로써 간단하게 observer pattern을 구현할 수 있다.
for msg := range c.incomingMsgChan {
select {
case c.memoryMsgChan <- msg:
default:
}
}
2. Cleanup with signal
- Graceful shutdown을 위한 flow control 구현 시 GO의 channel을 이용하면 간단하게 구현할 수 있다.
func work() {
exitChan := make(chan int)
go task1(exitChan)
go task2(exitChan)
time.Sleep(5 * time.Second)
close(exitChan)
}
func task1(exitChan chan int) {
<-exitChan
log.Printf("task1 exiting")
}
func task2(exitChan chan int) {
<-exitChan
log.Printf("task2 exiting")
}
- 2.를 실제 시스템에 적용할 때 Superloop를 두고 그 안에서 어떻게 동작하는 지를 보인다.
for {
select {
case <-n.workA:
// do work A
continue
case <-n.workB:
// do work B
continue
case <-n.exitChan
goto exit
}
}
- Multithread처럼 동작하는 Goroutine 간 동기화를 해주기위해서 1) atomic operation을 쓰는 방법과 2) lock mechanism을 이용하는 방법이 있다.
- Atomic operation은 GO에서 자체적으로 지원하는 CAS(Compare And Swap)라고 볼 수 있다. 변수에 대한 읽고쓰기의 transactional을 보장함으로써 동기화에 사용할 수 있다.
- Lock mechanism은 Mutex, Semaphore 등 널리 사용되는 기법들과 동일하다. Read lock도 지원한다.
- Atomic operation
- persist := atomic.LoadInt32(&n.isLoading) == 0
- Lock mechanism
- sync.Lock()
- sync.RLock()
5. Goroutine waitgroup
- Goroutine 이 끝나기 전에 Main thread가 종료되는걸 방지하기위해 goroutine 의 수행 완료를 기다리라 명시하는 모듈/함수
- WaitGroup.wait()
Reference
[1] NSQ, nsq.io
[2] NSQ Github, https://github.com/nsqio/nsq
댓글
댓글 쓰기