🐾 [golang] 고루틴 주의 사항
주의 사항 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("나쁜 예시 끝")
}
결과

해결 방안
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("좋은 예시 끝")
}
결과

주의 사항 2)
- 변수를 조심히 해야한다.
문제점
위에 코드의 예상값은 아래와 같을 것이다. 하지만 실제 값은 같은 수가 나올 때도 있고 다른 수가 나올 때도 있다. 수가 순서대로 나오지는 않는다.
예상값

이걸 해결하기 위한 방안 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