Heim  >  Artikel  >  Backend-Entwicklung  >  Golang-Parallelität ist keine Parallelität

Golang-Parallelität ist keine Parallelität

(*-*)浩
(*-*)浩Original
2019-12-17 11:52:222184Durchsuche

Golang-Parallelität ist keine Parallelität

Parallelität ist nicht gleichbedeutend mit Parallelität

Golang-Kernentwickler Rob Pike hat dieses Thema ausdrücklich erwähnt                                             go)

Obwohl wir go in der for-Schleife verwenden, um eine Goroutine zu erstellen, gehen wir davon aus, dass Golang jedes Mal, wenn wir eine Variable durchlaufen, diese Goroutine auf jeden Fall ausführt und dann die Variable zu diesem Zeitpunkt ausgibt.

Zu diesem Zeitpunkt verfielen wir in eine feste Denkweise. Die Standard-Parallelität entspricht Parallelität.

Es stimmt, dass die von go erstellte Goroutine den darin enthaltenen Funktionscode gleichzeitig ausführt.

Aber wird es jedes Mal ausgeführt, wenn wir eine Schleife ausführen, wie wir es uns vorgestellt haben?

Die Antwort ist nein!

Rob Pike erwähnte ausdrücklich, dass sich Parallelität in Golang auf die Tatsache bezieht, dass bestimmte Funktionen in der Codestruktur logisch gleichzeitig ausgeführt werden können, möglicherweise jedoch nicht physisch gleichzeitig. Unter Parallelität versteht man die Verwendung unterschiedlicher CPUs zur Ausführung unterschiedlicher oder gleicher Aufgaben auf physikalischer Ebene.

Golangs Goroutine-Planungsmodell bestimmt, dass jede Goroutine in einer virtuellen CPU ausgeführt wird (d. h. der Anzahl virtueller CPUs, die wir über runtime.GOMAXPROCS(1) festlegen).

Die Anzahl der virtuellen CPUs stimmt möglicherweise nicht mit der tatsächlichen Anzahl der CPUs überein. Jede Goroutine wird von einem bestimmten P (virtuelle CPU) ausgewählt und verwaltet, und M (physische Rechenressource) wählt jedes Mal ein gültiges P aus und führt dann die Goroutine in P aus.

Jedes P stellt die von ihm verwaltete Goroutine in eine G-Warteschlange, die Goroutine-Stack-Informationen, ausführbare Informationen usw. enthält. Standardmäßig entspricht die Anzahl der Ps der Anzahl der tatsächlichen physischen CPUs.

Wenn wir also Goroutinen durch Schleifen erstellen, wird jede Goroutine einer anderen P-Warteschlange zugewiesen. Die Anzahl von M ist nicht eindeutig. Wenn M P zufällig auswählt, entspricht dies der zufälligen Auswahl einer Goroutine.

In dieser Frage setzen wir P=1. Daher sind alle Goroutinen an dasselbe P gebunden. Wenn wir den Wert von runtime.GOMAXPROCS ändern, sehen wir eine andere Reihenfolge. Wenn wir die Goroutine-ID ausgeben, können wir den Effekt der zufälligen Auswahl sehen:

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()
}

Die Ausgabe ist wie folgt:

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

Wir kommen jedoch noch einmal auf diese Frage zurück in der Schleife Eine Goroutine wird durch go definiert. Aber wie gesagt, Parallelität bedeutet nicht Parallelität. Obwohl es definiert wurde, kann es daher zum jetzigen Zeitpunkt möglicherweise nicht implementiert werden.

Sie müssen warten, bis M P ausgewählt hat, bevor Sie die Goroutine ausführen. Informationen zur Planung von Goroutine in Golang (GPM-Modell) finden Sie im Scalable Go Scheduler Design Doc oder in LearnConcurrency

Das obige ist der detaillierte Inhalt vonGolang-Parallelität ist keine Parallelität. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn