반응형
# 주의 사항 1)
- wg.Add(1) 위치가 중요하다
- 고루틴을 실행하기 전에 wg.Add(1) 를 실행야한다. waitGroup의 초기화를 로직 처리 전에 해줘야 타이밍 이슈를 피할 수 있다.
- 동시성 이슈가 있어서 add는 고루틴 실행 전에 한꺼번에 초기화를 해주는 것이 좋다.
# 문제 발생
고루틴 안에서 add하고 done한다.
func BadExWaitGroup() {
fmt.Println("나쁜 예시 시작")
size := 10
var wg sync.WaitGroup
for i := 0; i < size; i++ {
go func() {
wg.Add(1)
fmt.Printf("진행 중 %d \n", i)
wg.Done()
}()
}
wg.Wait()
fmt.Println("나쁜 예시 끝")
}
결과
나쁜 예시 시작
나쁜 예시 끝
고루틴2로 들어가기 전에 wg가 0이 되어서 main은 끝났다고 인식한다. 그래서 고루틴2가 실행 되지 않고 종료가 됐다.
# 해결 방안
add를 10으로 하고 고루틴이 돈다. done이 10번 되야지 끝난다.
func GoodExWaitGroup() {
fmt.Println("좋은 예시 시작")
size := 10
var wg sync.WaitGroup
wg.Add(size)
for i := 0; i < size; i++ {
go func() {
fmt.Printf("진행 중 %d \n", i)
wg.Done()
}()
}
wg.Wait()
fmt.Println("좋은 예시 끝")
}
결과
좋은 예시 시작
진행 중 10
진행 중 10
진행 중 10
진행 중 10
진행 중 10
진행 중 10
진행 중 10
진행 중 10
진행 중 10
진행 중 10
좋은 예시 끝
위에 문제점만 해결이 되었다. 똑같은 수만 출력이 된다.
# 주의 사항 2)
- 변수를 조심히 해야한다.
# 문제점
위에 코드의 예상값은 아래와 같을 것이다. 하지만 실제 값은 같은 수가 나올 때도 있고 다른 수가 나올 때도 있다. 수가 순서대로 나오지는 않는다.
# 예상값
좋은 예시 시작
진행 중 0
진행 중 1
진행 중 2
진행 중 3
진행 중 4
진행 중 5
진행 중 6
진행 중 7
진행 중 8
진행 중 9
좋은 예시 끝
i = 0일 때 고루틴이 생성해서 새로운 고루틴을 만들었다. 메인에서는 i가 1일 때로 이동한다. 고루틴에서 i를 찾는 시점은 이미 i가 변경 된 후 이다. i가 0이라고 보장을 할 수 없다.
이걸 해결하기 위한 방안 2가지가 있다.
해결방안 1)
- golang 문법 이용
- i := i로 다시 정의 해준다
fmt.Println("해결책 one 시작")
size := 10
var wg sync.WaitGroup
wg.Add(size)
for i := 0; i < size; i++ {
i := i //여기 추가
go func() {
fmt.Printf("진행 중 %d \n", i)
wg.Done()
}()
}
wg.Wait()
fmt.Println("해결책 one 끝")
해결방안2)
- 고루틴 함수 내에서 사용하는 변수
- 고루틴을 생성하는 시점의 값을 넣어준다.
- 고루틴 함수에 i값을 넣어 준다. i값이 고루틴함수에 들어 왔기 때문에 i는 변하지 않고 고루틴 안에서만 유지할 수 있다.
func SolutionTwo() {
fmt.Println("해결책 two 시작")
size := 10
var wg sync.WaitGroup
wg.Add(size)
for i := 0; i < size; i++ {
go func(i int) {
fmt.Printf("진행 중 %d \n", i)
wg.Done()
}(i)
}
wg.Wait()
fmt.Println("해결책 two 끝")
}
# 참조
https://github.com/YooGenie/go-study/issues/56
반응형
'Study > Go 언어' 카테고리의 다른 글
[golang] context.WithCancel() 사용법 (0) | 2022.10.13 |
---|---|
[golang] context 역할 및 종류 (0) | 2022.10.12 |
[golang] 고루틴이 끝나기 전에 main이 끝나는 문제 해결 방법 (0) | 2022.10.10 |
[golang] 고루틴(goroutine) 기본 문법 (0) | 2022.10.09 |
[golang] 채널(channel) blocking 해결 방법 (0) | 2022.10.07 |