개요 (Overview)
Golang에서 실행 중인 고루틴의 흐름을 제어할 수 있는 방법은 컨텍스트(Context) 외에도 채널(Channel)을 사용하여 흐름 제어를 할 수 있다. 채널은 다른 언어에서 일반적으로 큐(Queue)와 동일한 역할을 하고 있지만 Golang에서의 채널은 큐 외에도 흐름 제어의 역할도 가능하다. 채널은 기본적으로 별도의 동기 작업 없이도 안전하기 때문에 고루틴에서도 사용 가능하다. 참고로 Golang에서 쓰레드는 런타임 내부에서만 관리되며 개발자가 쓰레드를 제어할 수 있는 방법은 없다.
채널 (Channel)
기본적으로 큐의 역할을 한다.
아래 문서는 채널을 편하게 사용하기 위한 헬퍼 함수와 관련 변수들이 정의된 패키지이며 실제 채널 자체에 대해 다루는 문서는 아니다. 그리고 운영 환경에서 import 하는 것을 권장하지 않는다. (*Go의 타입 시스템의 한계 때문이라는데 이건 추후 확인)
channels package - github.com/eapache/channels - Go Packages
기본적인 사용 방법은 Effective Go 문서에서 확인할 수 있다.
Effective Go - The Go Programming Language
채널 생성
func main() {
// 버퍼가 없는 bool 타입의 채널을 생성
unBufferedChan := make(chan bool)
// 버퍼가 없는 string 타입의 채널을 생성
unBufferedChan := make(chan string, 0)
// 버퍼가 10만큼 있는 string 타입의 채널을 생성
bufferedChan := make(chan string, 10)
}
채널에 데이터 처리 (넣기/가져오기)
func main() {
// 버퍼가 없는 bool 타입의 채널을 생성
unBufferedChan := make(chan bool)
// 채널에 true 데이터 넣기
unBufferedChan <- true
// 채널에 true 데이터 가져오기
result := <-unBufferedChan
}
채널 닫기
func main() {
// 버퍼가 없는 bool 타입의 채널을 생성
unBufferedChan := make(chan bool)
// 채널 닫기
close(unBufferedChan)
}
사용 방법 (How to use)
함수 처리 중 특정 사유(인터럽트, 에러 등)로 인한 고루틴 흐름 제어 (채널 닫기)
- 타입에 관계 없이 채널 생성 (단순하게 bool 타입)
- 생성된 채널을 포함하여 고루틴 생성
- 작업 (메인 함수는 고루틴 완료 대기)
- 인터럽트 또는 메인 함수에서 에러가 발생하여 채널 닫기(close)
- 채널이 닫힌 후 실행 중인 고루틴이 모두 종료될 때까지 대기
- 모두 종료 후 메인 함수 정리 후 종료
샘플 코드 (Sample code)
이전 글과 동일하게 고루틴의 상태를 확인하기 위해 sync.WaitGroup을 사용
package main
import (
"log"
"sync"
"time"
)
// user defined asynchronous task
func async_task(wg *sync.WaitGroup, stopEvent <-chan bool, i int) {
for {
select {
case <-stopEvent:
// using break does not escape for-loop
// should use return instead or flag
log.Printf("terminate async task %d", i)
wg.Done()
return
default:
log.Printf("async task %d is running", i)
time.Sleep(time.Duration(i) * time.Second)
}
}
}
func main() {
log.Printf("start channel-goroutine-manage")
waitGroup := sync.WaitGroup{}
stopEvent := make(chan bool)
// run goroutines
for i := 1; i <= 3; i++ {
waitGroup.Add(1)
go async_task(&waitGroup, stopEvent, i)
}
// stop goroutines after 10 seconds
go func() {
log.Printf("wait for 10 seconds")
time.Sleep(time.Duration(10) * time.Second)
log.Printf("time is over, close channel")
close(stopEvent)
}()
// wait goroutines
log.Printf("wait goroutines")
waitGroup.Wait()
log.Printf("all goroutines are terminated")
log.Printf("terminate basic-goroutine-manage")
}
'Developer > Go' 카테고리의 다른 글
Golang 고루틴(goroutine) 라이프사이클 관리 - context.Context (0) | 2024.04.21 |
---|---|
컨테이너 환경에서 GOMAXPROCS 이슈 (0) | 2024.01.17 |
Golang defer 실행 순서 (1) | 2024.01.07 |