-
Go에서 채널(Channel)을 이용한 고루틴(Goroutine) 개수 제한Go 2025. 4. 3. 00:32
Go의 goroutine은 가벼운 스레드로, 다른 언어보다 손쉽게 동시성을 확보할 수 있게 한다. 하지만 무제한으로 생성하면 메모리 부족이나 시스템 리소스 과부하가 발생할 수 있기 때문에 goroutine의 개수를 제한하는 방법이 필요하다. 이번 글에서는 channel을 이용해 goroutine 개수를 제한하는 방법을 공유한다.
package main import ( "fmt" "sync" "time" ) func main() { maxGoroutines := 10 // 동시에 실행할 최대 goroutine 개수 semaphore := make(chan struct{}, maxGoroutines) var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) go func(id int) { defer wg.Done() semaphore <- struct{}{} // 세마포어 역할 (슬롯 점유) defer func() { <-semaphore }() // 작업 종료 후 슬롯 반환 // 실제 작업 수행 fmt.Printf("Goroutine %d 실행 중\n", id) time.Sleep(1 * time.Second) // 작업 시뮬레이션 }(i) } wg.Wait() fmt.Println("모든 작업 완료") }
코드 설명
1. 버퍼드 채널을 세마포어로 사용
semaphore := make(chan struct{}, maxGoroutines)
- maxGoroutines 개수만큼 버퍼를 가진 채널을 생성한다.
- 동시에 실행될 수 있는 goroutine의 개수를 제한하는 역할을 한다.
2. goroutine 시작 전 채널에 값 추가
semaphore <- struct{}{}
- 채널에 값을 넣으면서 실행 가능한 goroutine 개수를 제한한다.
- maxGoroutines 개수만큼만 값이 들어갈 수 있으며, 초과할 경우 블로킹된다.
3. goroutine 종료 후 채널에서 값 제거
defer func() { <-semaphore }()
- 작업이 끝나면 채널에서 값을 제거하여, 새로운 goroutine이 실행될 수 있도록 허용한다.
- defer를 사용해 goroutine이 종료될 때 자동으로 실행되도록 한다.
4. WaitGroup을 사용하여 모든 goroutine의 종료 대기
var wg sync.WaitGroup wg.Add(1) // goroutine 실행 전 카운트 증가 defer wg.Done() // goroutine 종료 시 카운트 감소 wg.Wait() // 모든 goroutine 종료까지 대기
- WaitGroup을 사용하여 모든 goroutine이 종료될 때까지 기다린다.
실행 결과
Goroutine 0 실행 중 Goroutine 1 실행 중 Goroutine 2 실행 중 ... Goroutine 9 실행 중 (1초 후) Goroutine 10 실행 중 Goroutine 11 실행 중 ... Goroutine 19 실행 중 모든 작업 완료
- 최대 10개의 goroutine이 동시에 실행된다
- 앞의 작업이 끝나야 다음 goroutine이 실행된다.
요약
- 채널을 세마포어처럼 활용하여 goroutine 개수를 제한할 수 있다.
- defer를 이용해 깔끔하게 자원을 반환할 수 있다.
- sync.WaitGroup을 함께 사용하면 모든 작업이 끝날 때까지 대기할 수 있다.