Skip to content

Instantly share code, notes, and snippets.

@ezaurum
Last active June 27, 2020 11:07
Show Gist options
  • Save ezaurum/4f23c90f322ef403af4372c74d1b2346 to your computer and use it in GitHub Desktop.
Save ezaurum/4f23c90f322ef403af4372c74d1b2346 to your computer and use it in GitHub Desktop.
range 로 만든 변수를 사용시 고려할 점
package main
import (
"fmt"
"sync"
)
var (
test = []string{
"11B804806F367001",
"11B804806F367002",
"11B804806F767051",
}
)
func main() {
wg := sync.WaitGroup{}
wg.Add(len(test) * 2)
for i, s := range test {
// 결과가 생각한 대로 나오나요?
go func() {
fmt.Printf("start %d - %s\n", i, s)
wg.Done()
}()
// 이 라인은 어째서 쓸까요? :D
idx, str := i, s
go func() {
fmt.Printf("start2 %d - %s\n", idx, str)
wg.Done()
}()
}
wg.Wait()
}
@ElsieKim
Copy link

ElsieKim commented Jun 27, 2020

위의 start는, 고루틴이 for문이 종료된 후에 실행되기 때문에, for의 마지막 값 (i == 2 , s==...051)들고 있으므로
같은 값들만 세 번 출력됩니다.

그에 반해, 밑의 start2의 경우 idx, str := i, s 이 두 변수가 for문이 도는 동안 스코프 내에서 새로 생성되어서
그 때 그 때의 i, s의 값을 복사해서 들고 있습니다.
때문에 실행 시점에는 각 idx, str이 들고있던 값들을 바르게 출력합니다.

그리고, 실행 할 때마다 출력이 다른 이유는 go func가 CPU의 사정에 따라 아주 미묘하게 처리가 다르기 때문입니다. (6개를 동시처리 하므로)

@ezaurum
Copy link
Author

ezaurum commented Jun 27, 2020

위의 start는, 고루틴이 for문이 종료된 후에 실행되기 때문에, for의 마지막 값 (i == 2 , s==...051)들고 있으므로
같은 값들만 세 번 출력됩니다.

고루틴은 for가 다 돌고 나서 실행될 수도 있고, 중간에 실행될 수도 있습니다. 하지만 for문이 도는 속도가 더 빠를 것이므로 보통의 경우는 다 돌고 내부로직이 돌겠죠.
마지막 값을 가지고 있는 것도 맞습니다.
그 원인은 for 내부에서 i, s를 재사용하기 때문입니다.

그에 반해, 밑의 start2의 경우 idx, str := i, s 이 두 변수가 for문이 도는 동안 스코프 내에서 새로 생성되어서
그 때 그 때의 i, s의 값을 복사해서 들고 있습니다.
때문에 실행 시점에는 각 idx, str이 들고있던 값들을 바르게 출력합니다.

맞습니다.
그래서 for 내부에서는 값 사용에 주의해야 합니다.

그리고, 실행 할 때마다 출력이 다른 이유는 go func가 CPU의 사정에 따라 아주 미묘하게 처리가 다르기 때문입니다. (6개를 동시처리 하므로)

맞습니다. 고루틴은 실행 순서를 보장하지 않습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment