`errgroup`을 사용하여 Go에서 동시 작업 관리하기
James Reed
Infrastructure Engineer · Leapcell

Key Takeaways
errgroup
은 오류 처리 및 컨텍스트 취소와 함께 동시 Goroutine 관리를 단순화합니다.WithContext
를 사용하면 실패 시 모든 Goroutine을 조기에 종료할 수 있습니다.SetLimit
은 리소스 사용을 최적화하기 위해 활성 동시 Goroutine의 수를 제어합니다.
Go의 errgroup
패키지는 공통 작업의 하위 작업에서 작동하는 Goroutine 그룹에 대한 동기화, 오류 전파 및 컨텍스트 취소를 제공합니다. 이는 golang.org/x/sync
모듈의 일부이며 오류를 반환할 수 있는 동시 작업을 관리하는 편리한 방법을 제공합니다.
errgroup
개요
errgroup
패키지는 관련된 작업을 수행하는 여러 Goroutine의 관리를 단순화하도록 설계되었습니다. 오류 처리 및 컨텍스트 취소 기능을 추가하여 sync.WaitGroup
의 기능을 확장합니다. 즉, Goroutine이 오류를 발견하면 전체 그룹을 취소할 수 있고 오류를 호출자에게 다시 전파할 수 있습니다.
주요 구성 요소
errgroup
패키지의 주요 구성 요소는 다음과 같습니다.
- Group: 동일한 전체 작업의 하위 작업에서 작동하는 Goroutine 모음입니다.
- WithContext: 제공된 컨텍스트에서 파생된 새
Group
및 관련Context
를 만듭니다. - Go: 새 Goroutine에서 실행될 함수를 등록합니다.
- Wait: 등록된 모든 함수가 완료될 때까지 기다리고 첫 번째 nil이 아닌 오류(있는 경우)를 반환합니다.
기본 사용법
다음은 errgroup
을 사용하여 여러 URL을 동시에 가져오는 방법의 예입니다.
package main import ( "fmt" "net/http" "golang.org/x/sync/errgroup" ) func main() { var g errgroup.Group var urls = []string{ "http://www.golang.org/", "http://www.google.com/", "http://www.somestupidname.com/", } for _, url := range urls { url := url // 클로저 문제를 피하기 위해 새 변수 만들기 g.Go(func() error { resp, err := http.Get(url) if err == nil { resp.Body.Close() } return err }) } if err := g.Wait(); err == nil { fmt.Println("Successfully fetched all URLs.") } else { fmt.Printf("Failed to fetch URLs: %v\n", err) } }
이 예에서는 errgroup.Group
이 생성되고 각 URL에 대해 HTTP GET 요청을 수행하기 위해 새 Goroutine이 시작됩니다. g.Go
메서드는 동시에 실행될 함수를 등록합니다. g.Wait
메서드는 모든 Goroutine이 완료될 때까지 기다리고 발생한 첫 번째 오류(있는 경우)를 반환합니다.
컨텍스트와 함께 errgroup
사용
WithContext
함수는 컨텍스트 취소를 허용하여 Goroutine 중 하나가 오류를 발견하면 모든 Goroutine을 취소할 수 있도록 합니다. 이는 작업이 상호 의존적이거나 실패 시 조기 종료가 필요한 경우에 특히 유용합니다.
package main import ( "context" "fmt" "golang.org/x/sync/errgroup" "time" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() g, ctx := errgroup.WithContext(ctx) for i := 0; i < 3; i++ { i := i // 클로저 캡처 방지 g.Go(func() error { if i == 1 { return fmt.Errorf("error in goroutine %d", i) } select { case <-time.After(2 * time.Second): fmt.Printf("goroutine %d completed\n", i) case <-ctx.Done(): fmt.Printf("goroutine %d canceled\n", i) } return nil }) } if err := g.Wait(); err != nil { fmt.Printf("Group finished with error: %v\n", err) } else { fmt.Println("Group finished successfully") } }
이 코드에서 Goroutine이 오류를 반환하면 컨텍스트가 취소되어 다른 Goroutine이 컨텍스트의 취소를 존중하는 경우 조기에 종료됩니다.
SetLimit
으로 동시성 제어
SetLimit
메서드를 사용하면 특정 시점에 활성 Goroutine의 최대 수를 제어할 수 있습니다. 이는 많은 수의 작업을 처리할 때 리소스 사용을 제한하는 데 유용합니다.
package main import ( "fmt" "golang.org/x/sync/errgroup" ) func main() { var g errgroup.Group g.SetLimit(2) // 2개의 동시 Goroutine으로 제한 for i := 0; i < 5; i++ { i := i // 클로저 캡처 방지 g.Go(func() error { fmt.Printf("Starting task %d\n", i) // 작업 시뮬레이션 return nil }) } if err := g.Wait(); err != nil { fmt.Printf("Group finished with error: %v\n", err) } else { fmt.Println("Group finished successfully") } }
여기서 SetLimit(2)
는 두 개 이하의 Goroutine이 동시에 활성 상태로 유지되도록 합니다. 새 Goroutine은 활성 Goroutine이 완료될 때까지 시작되기 전에 기다립니다.
일반적인 함정
errgroup
을 사용할 때는 다음 사항에 유의하십시오.
-
클로저에서 변수 캡처: 예기치 않은 동작을 방지하려면 루프 변수가 클로저에서 올바르게 캡처되었는지 확인하십시오. 이는 일반적으로 루프 내에서 새 변수를 만들어 수행됩니다.
-
컨텍스트 취소:
WithContext
를 사용하는 경우 Goroutine은 취소 시 즉시 종료하기 위해ctx.Done()
을 확인하여 컨텍스트의 취소를 존중해야 합니다. -
오류 처리:
errgroup
은 첫 번째 nil이 아닌 오류만 캡처합니다. 모든 오류를 수집해야 하는 경우 추가 오류 집계 논리를 구현해야 합니다.
errgroup
패키지를 활용하여 Go 개발자는 내장된 오류 처리 및 컨텍스트 인식 취소 기능을 통해 복잡한 동시 워크플로를 보다 효과적으로 관리할 수 있습니다.
FAQs
errgroup
은 오류를 전파하고 컨텍스트 취소를 지원하는 반면 sync.WaitGroup
은 Goroutine이 완료될 때까지 기다립니다.
첫 번째 오류가 반환되고 WithContext
를 사용하는 경우 다른 Goroutine은 취소 신호를 받습니다.
SetLimit(n)
을 사용하여 n
개의 Goroutine만 동시에 실행되도록 합니다.
Leapcell은 Go 프로젝트 호스팅을 위한 최고의 선택입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하십시오.
무제한 프로젝트를 무료로 배포
- 사용량에 대해서만 지불하십시오. 요청도 없고 요금도 없습니다.
탁월한 비용 효율성
- 유휴 요금 없이 사용한 만큼 지불하십시오.
- 예: $25는 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 간편한 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
손쉬운 확장성 및 고성능
- 고도의 동시성을 쉽게 처리하기 위한 자동 확장.
- 운영 오버헤드가 전혀 없으므로 구축에만 집중하십시오.
설명서에서 자세히 알아보십시오!
X에서 팔로우하세요: @LeapcellHQ