Go 언어의 `sync.WaitGroup`은 어떤 용도로 사용되나요?
_____A: `sync.WaitGroup`은 여러 고루틴(goroutine)의 완료를 기다리기 위해 사용하는 동기화 도구입니다. 메인 고루틴이나 다른 고루틴이 여러 비동기 작업이 모두 끝날 때까지 블로킹할 수 있게 도와줍니다.
Q: `sync.WaitGroup`은 어떻게 사용하나요?
A: 주로 다음과 같이 사용합니다:
1. `Add(n int)` 메서드를 호출해 기다릴 고루틴 수를 설정합니다.
2. 각 고루틴 안에서 작업이 끝나면 `Done()` 메서드를 호출해 완료를 알립니다.
3. 기다리는 쪽에서는 `Wait()` 메서드를 호출해 모든 고루틴이 끝날 때까지 대기합니다.
Q: `Add()` 메서드와 `Done()` 메서드는 어떤 관계인가요?
A: `Add(n)`은 기다릴 작업 수를 증가시키며, `Done()`은 완료된 작업 수 1을 감소시킵니다. 내부 카운터가 0이 되면 `Wait()` 호출부가 즉시 반환됩니다.
Q: `Wait()` 메서드는 무엇을 하나요?
A: `Wait()`은 `Add()`로 지정한 작업 수만큼 `Done()` 호출이 이루어져 내부 카운터가 0이 될 때까지 호출한 고루틴을 블로킹합니다.
Q: `sync.WaitGroup` 사용 시 주의할 점은 무엇인가요?
A:
- `Add()` 호출은 절대 `Wait()` 호출 이후에 하면 안 됩니다. `Add()`는 기다릴 고루틴 시작 전에 호출해야 합니다.
- `WaitGroup` 값은 복사하지 말고 포인터로 전달해야 합니다.
- 과도하게 큰 수를 `Add()`하면 오버플로우가 발생할 수 있습니다.
- `Done()` 호출은 반드시 `Add()` 호출한 수만큼 정확히 이루어져야 하며, 그렇지 않으면 `Wait()`가 무한 대기할 수 있습니다.
A:
```go
var wg sync.WaitGroup
wg.Add(3) // 총 3개의 고루틴을 기다림
for i := 0; i < 3; i++ {
go func(id int) {
defer wg.Done()
// 작업 수행
fmt.Println("고루틴", id, "작업 완료")
}(i)
}
wg.Wait() // 모든 고루틴 완료 대기
fmt.Println("모든 작업 완료")
```
Q: 왜 `sync.WaitGroup`을 사용하나요?
A: 여러 고루틴이 동시에 실행될 때 모든 작업이 종료될 때까지 기다리는 동기화 작업을 편리하고 안전하게 할 수 있기 때문입니다. 임의의 sleep이나 복잡한 채널 등보다 직관적이고 실수 가능성을 줄여줍니다.
Q: `sync.WaitGroup`과 채널을 통한 동기화 차이는?
A: `WaitGroup`은 작업 완료 대기 목적에 특화되어 있어 간단하고 효율적이며, 채널은 작업 간 데이터 전달이나 이벤트 전달에 적합합니다. 동시에 여러 고루틴 종료를 기다릴 때는 `WaitGroup`이 보통 편리합니다.
여러 개의 고루틴이 동시에 실행될 때, 특정 작업이 모두 완료될 때까지 기다리거나, 특정 조건이 충족될 때까지 대기해야 할 필요가 있을 때 유용합니다.
`WaitGroup`은 이러한 동기화 작업을 간편하게 처리할 수 있도록 도와줍니다.
기본 개념 `WaitGroup`은 다음과 같은 세 가지 주요 메서드를 제공합니다: 1. Add(int) : 대기할 고루틴의 수를 설정합니다.
이 메서드는 대기할 고루틴의 수를 증가시키거나 감소시킬 수 있습니다.
예를 들어, 새로운 고루틴을 시작할 때마다 `Add(1)`을 호출하고, 고루틴이 완료되면 `Done()`을 호출하여 카운트를 감소시킵니다.
2. Done() : 고루틴이 작업을 완료했음을 알리는 메서드입니다.
이 메서드를 호출하면 `WaitGroup`의 카운트가 1 감소합니다.
3. Wait() : 모든 고루틴이 완료될 때까지 대기하는 메서드입니다.
이 메서드는 `Add()`로 설정된 카운트가 0이 될 때까지 블록(block)됩니다.
사용 예시 다음은 `sync.WaitGroup`을 사용하는 간단한 예제입니다: ```go package main import ( "fmt" "sync" "time" ) func worker(id int, wg *sync.WaitGroup) { defer wg.Done() // 작업이 끝나면 Done() 호출 fmt.Printf("Worker %d starting\n", id) time.Sleep(time.Second) // 작업 시뮬레이션 fmt.Printf("Worker %d done\n", id) } func main() { var wg sync.WaitGroup for i := 1; i <= 5; i++ { wg.Add(1) // 새로운 고루틴 추가 go worker(i, &wg) // 고루틴 시작 } wg.Wait() // 모든 고루틴이 완료될 때까지 대기 fmt.Println("All workers done") } ``` 위의 예제에서 `worker` 함수는 고루틴으로 실행되며, 각 고루틴이 시작될 때 `wg.Add(1)`을 호출하여 대기할 고루틴의 수를 증가시킵니다.
고루틴이 작업을 완료하면 `wg.Done()`을 호출하여 카운트를 감소시킵니다.
`main` 함수에서는 `wg.Wait()`을 호출하여 모든 고루틴이 완료될 때까지 대기합니다.
주의사항 - 스레드 안전성 : `WaitGroup`은 내부적으로 스레드 안전하게 설계되어 있어 여러 고루틴에서 동시에 `Add`, `Done`, `Wait` 메서드를 호출해도 안전합니다.
- 카운트 관리 : `Add` 메서드는 음수 값을 허용하지 않으며, 카운트가 0보다 작아지면 패닉이 발생합니다.
따라서 고루틴의 수를 정확하게 관리하는 것이 중요합니다.
- Wait 호출 후 : `Wait` 메서드를 호출한 후에는 `Add` 또는 `Done`을 호출하면 안 됩니다.
이는 정의된 동작이 아니며, 프로그램이 패닉을 일으킬 수 있습니다.
결론 `sync.WaitGroup`은 Go 언어에서 고루틴 간의 동기화를 간편하게 처리할 수 있는 강력한 도구입니다.
여러 고루틴이 동시에 실행되는 환경에서 작업의 완료를 기다리거나, 특정 조건이 충족될 때까지 대기해야 할 경우에 매우 유용합니다.
이를 통해 개발자는 복잡한 동기화 로직을 간소화하고, 코드의 가독성과 유지보수성을 높일 수 있습니다.
작성자:
정다은 [비회원]
| 작성일자: 1년 전
2024-09-19 01:50:37
조회수: 162 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
조회수: 162 | 댓글: 0 | 좋아요: 0 | 싫어요: 0
내용이 부정확하다면 싫어요를 클릭해주세요.