Useful GO coding pattern

프로그래밍 언어 GO 작성 시 유용한 패턴에 대해 공유한다.


1. Broadcasting with observer pattern
  • 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")
}

3. Superloop considering cleanup
  • 2.를 실제 시스템에 적용할 때 Superloop를 두고 그 안에서 어떻게 동작하는 지를 보인다.
for {
    select {
    case <-n.workA:
        // do work A
        continue
    case <-n.workB:
        // do work B
        continue
    case <-n.exitChan
        goto exit
    }
}

4. Synchronization
  • Multithread처럼 동작하는 Goroutine 간 동기화를 해주기위해서 1) atomic operation을 쓰는 방법과 2) lock mechanism을 이용하는 방법이 있다.
  • Atomic operation은 GO에서 자체적으로 지원하는 CAS(Compare And Swap)라고 볼 수 있다. 변수에 대한 읽고쓰기의 transactional을 보장함으로써 동기화에 사용할 수 있다.
  • Lock mechanism은 Mutex, Semaphore 등 널리 사용되는 기법들과 동일하다. Read lock도 지원한다.
  1. Atomic operation
    • persist := atomic.LoadInt32(&n.isLoading) == 0
  2. 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

댓글

이 블로그의 인기 게시물

JVM Thread & Memory Monitoring

Cocos2d-x Scene 전환 방법

GUI for Redis : Medis