>  기사  >  백엔드 개발  >  golang 동시성은 병렬성이 아닙니다

golang 동시성은 병렬성이 아닙니다

(*-*)浩
(*-*)浩원래의
2019-12-17 11:52:222157검색

golang의 핵심 개발자 Rob Pike가 구체적으로 언급한 주제는                                                                                                                                                (권장 학습:

gogolang 동시성은 병렬성이 아닙니다)

for 루프에서 go를 사용하여 고루틴을 생성하지만 자연스럽게 변수가 반복될 때마다 golang 이 고루틴은 반드시 실행되고 그때의 변수가 출력될 것이라고 생각하세요. 이때 우리는 고정관념에 빠졌습니다. 기본 동시성은 병렬성과 같습니다.

go를 통해 생성된 고루틴은 함수 코드를 동시에 실행하는 것이 사실입니다.

그런데 우리가 상상한대로 루프를 돌릴 때마다 실행이 될까요?

대답은 '아니오'입니다!

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.