Atomare Zähler in Go bei der Verwendung von Goroutinen

GolangGolangBeginner
Jetzt üben

This tutorial is from open-source community. Access the source code

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab geht es darum, den Zustand in Go mit dem Paket sync/atomic zu verwalten, um atomare Zähler zu verwenden, die von mehreren Goroutinen zugegriffen werden.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL go(("Golang")) -.-> go/ConcurrencyGroup(["Concurrency"]) go/ConcurrencyGroup -.-> go/atomic("Atomic") subgraph Lab Skills go/atomic -.-> lab-15454{{"Atomare Zähler in Go bei der Verwendung von Goroutinen"}} end

Atomare Zähler

Das Problem besteht darin, einen Zähler genau 1000 Mal zu erhöhen, indem 50 Goroutinen und das Paket sync/atomic verwendet werden.

  • Verwenden Sie das Paket sync/atomic, um den Zähler zu erhöhen.
  • Verwenden Sie eine WaitGroup, um auf alle Goroutinen zu warten, bis sie ihre Arbeit beendet haben.
## Wir erwarten genau 50.000 Operationen. Hätten wir
## den nicht-atomaren `ops++` verwendet, um den Zähler
## zu erhöhen, würden wir wahrscheinlich eine andere
## Zahl erhalten, die zwischen den Ausführungen
## variiert, da die Goroutinen sich gegenseitig
## stören würden. Darüber hinaus würden wir bei der
## Ausführung mit der `-race`-Flagge Datenkonfliktfehler
## erhalten.
$ go run atomic-counters.go
ops: 50000

## Als nächstes werden wir uns Mutexs ansehen, ein anderes
## Werkzeug zum Verwalten des Zustands.

Hier ist der vollständige Code:

// Der primäre Mechanismus zum Verwalten des Zustands in Go ist
// die Kommunikation über Kanäle. Wir haben das beispielsweise
// bei [Arbeitskräftepools](worker-pools) gesehen. Es gibt jedoch
// einige andere Optionen zum Verwalten des Zustands. Hier
// werden wir das Paket `sync/atomic` für _atomare Zähler_
// verwenden, die von mehreren Goroutinen zugegriffen werden.

package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

func main() {

	// Wir verwenden eine unsigned Integer, um unseren
	// (immer positiven) Zähler darzustellen.
	var ops uint64

	// Eine WaitGroup wird uns helfen, auf alle Goroutinen
	// zu warten, bis sie ihre Arbeit beendet haben.
	var wg sync.WaitGroup

	// Wir starten 50 Goroutinen, die jeweils den Zähler
	// genau 1000 Mal erhöhen.
	for i := 0; i < 50; i++ {
		wg.Add(1)

		go func() {
			for c := 0; c < 1000; c++ {
				// Um den Zähler atomar zu erhöhen, verwenden
				// wir `AddUint64` und geben ihm die Speicheradresse
				// unseres `ops`-Zählers mit der `&`-Syntax.
				atomic.AddUint64(&ops, 1)
			}
			wg.Done()
		}()
	}

	// Warten Sie, bis alle Goroutinen fertig sind.
	wg.Wait()

	// Es ist jetzt sicher, auf `ops` zuzugreifen, da wir wissen,
	// dass keine andere Goroutine darauf schreibt. Es ist auch
	// möglich, atomare Werte sicher zu lesen, während sie
	// aktualisiert werden, indem Funktionen wie
	// `atomic.LoadUint64` verwendet werden.
	fmt.Println("ops:", ops)
}

Zusammenfassung

In diesem Lab haben wir gelernt, wie das Paket sync/atomic in Go verwendet wird, um den Zustand zu verwalten, indem ein Zähler mit mehreren Goroutinen erhöht wird. Die Funktion AddUint64 wurde verwendet, um den Zähler atomar zu erhöhen, und eine WaitGroup wurde verwendet, um auf alle Goroutinen zu warten, bis sie ihre Arbeit beendet haben.