golang의 핵심 개발자 Rob Pike가 구체적으로 언급한 주제는 (권장 학습:
go)
for 루프에서 go를 사용하여 고루틴을 생성하지만 자연스럽게 변수가 반복될 때마다 golang 이 고루틴은 반드시 실행되고 그때의 변수가 출력될 것이라고 생각하세요. 이때 우리는 고정관념에 빠졌습니다. 기본 동시성은 병렬성과 같습니다.
그런데 우리가 상상한대로 루프를 돌릴 때마다 실행이 될까요?
대답은 '아니오'입니다!Rob Pike는 Golang의 동시성이란 코드 구조의 특정 기능이 논리적으로는 동시에 실행될 수 있지만 물리적으로는 동시에 실행되지 않을 수 있음을 의미한다고 구체적으로 언급했습니다. 병렬성은 물리적 수준에서 서로 다르거나 동일한 작업을 수행하기 위해 서로 다른 CPU를 사용하는 것을 의미합니다.
Golang의 고루틴 스케줄링 모델은 각 고루틴이 가상 CPU(즉, Runtime.GOMAXPROCS(1)를 통해 설정한 가상 CPU 수)에서 실행되도록 결정합니다.
가상 CPU 수는 실제 CPU 수와 일치하지 않을 수 있습니다. 각 고루틴은 특정 P(가상 CPU)에 의해 선택 및 유지 관리되며 M(물리적 컴퓨팅 리소스)은 매번 유효한 P를 선택한 다음 P에서 고루틴을 실행합니다. 각 P는 자신이 유지 관리하는 고루틴을 G 대기열에 넣습니다. 여기에는 고루틴 스택 정보, 실행 가능 정보 등이 포함됩니다. 기본적으로 P의 수는 실제 물리적 CPU 수와 동일합니다.따라서 루프를 통해 고루틴을 생성하면 각 고루틴이 다른 P 대기열에 할당됩니다. M의 개수는 고유하지 않습니다. M이 P를 무작위로 선택하는 것은 고루틴을 무작위로 선택하는 것과 같습니다.
이 질문에서는 P=1로 설정했습니다. 따라서 모든 고루틴은 동일한 P에 바인딩됩니다. Runtime.GOMAXPROCS의 값을 수정하면 다른 순서가 표시됩니다. 고루틴 ID를 출력하면 무작위 선택의 효과를 볼 수 있습니다.func main() { wg := sync.WaitGroup{} wg.Add(20) for i := 0; i < 10; i++ { go func() { var buf [64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Sprintf("cannot get goroutine id: %v", err)) } fmt.Println("go routine 1 i: ", i, id) wg.Done() }() } for i := 0; i < 10; i++ { go func(i int) { var buf [64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Sprintf("cannot get goroutine id: %v", err)) } fmt.Println("go routine 2 i: ", i, id) wg.Done() }(i) } wg.Wait() }
출력은 다음과 같습니다.
go routine 2 i: 9 24 go routine 1 i: 10 11 go routine 1 i: 10 5 go routine 1 i: 10 6 go routine 2 i: 3 18 go routine 1 i: 10 9 go routine 1 i: 10 10 go routine 1 i: 10 8 go routine 2 i: 0 15 go routine 2 i: 4 19 go routine 2 i: 6 21 go routine 1 i: 10 7 go routine 1 i: 10 14 go routine 2 i: 7 22 go routine 2 i: 8 23 go routine 1 i: 10 13 go routine 2 i: 5 20 go routine 1 i: 10 12 go routine 2 i: 1 16 go routine 2 i: 2 17 ⋊> ~/S/g/g/s/t/C/goroutine ./goroutine go routine 1 i: 10 11 go routine 2 i: 9 24 go routine 1 i: 10 6 go routine 1 i: 10 14 go routine 1 i: 10 9 go routine 1 i: 10 10 go routine 1 i: 10 12 go routine 2 i: 0 15 go routine 1 i: 10 13 go routine 1 i: 10 5 go routine 2 i: 1 16 go routine 2 i: 5 20 go routine 1 i: 10 7 go routine 2 i: 7 22 go routine 2 i: 3 18 go routine 2 i: 2 17 go routine 2 i: 4 19 go routine 1 i: 10 8 go routine 2 i: 8 23 go routine 2 i: 6 21가자 back to this 질문에서, goroutine은 go in the loop를 통해 정의되었지만. 그러나 우리가 말했듯이 동시성은 병렬성을 의미하지 않습니다. 따라서 정의되었더라도 현재로서는 구현되지 않을 수도 있습니다. 고루틴을 실행하기 전에 M이 P를 선택할 때까지 기다려야 합니다. golang(GPM 모델)에서 고루틴이 어떻게 예약되는지에 대해서는 Scalable Go Scheduler Design Doc 또는 LearnConcurrency
를 참조하세요.
위 내용은 golang 동시성은 병렬성이 아닙니다의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!