Heim  >  Artikel  >  Backend-Entwicklung  >  Wie verwende ich Sperren in Go?

Wie verwende ich Sperren in Go?

PHPz
PHPzOriginal
2023-05-11 15:33:062410Durchsuche

Bei der gleichzeitigen Programmierung ist Sperren ein Mechanismus zum Schutz gemeinsam genutzter Ressourcen. In der Go-Sprache sind Sperren eines der wichtigen Werkzeuge zum Erreichen von Parallelität. Es stellt sicher, dass beim gleichzeitigen Zugriff mehrerer Coroutinen auf gemeinsam genutzte Ressourcen nur eine Coroutine diese Ressourcen lesen oder ändern kann. In diesem Artikel wird die Verwendung von Sperren in der Go-Sprache vorgestellt, um den Lesern ein besseres Verständnis der gleichzeitigen Programmierung zu ermöglichen.

  1. Mutual Exclusion Lock

Mutual Exclusion Lock ist der am häufigsten verwendete Sperrmechanismus in der Go-Sprache. Dadurch wird sichergestellt, dass nur eine Coroutine gleichzeitig auf den kritischen Abschnitt zugreifen kann. Laienhaft ausgedrückt stellt eine Mutex-Sperre sicher, dass nur eine Coroutine gleichzeitig darauf zugreifen kann, indem gemeinsam genutzte Ressourcen in einen sperrenkritischen Abschnitt eingeschlossen werden.

Die Verwendung von Mutex-Sperren in der Go-Sprache ist sehr einfach. Wir können den Mutex-Typ im Synchronisierungspaket verwenden, um eine Mutex-Sperre zu erstellen:

import "sync"

var mutex = &sync.Mutex{}

Danach können wir an dem Ort, an dem gemeinsam genutzte Ressourcen geschützt werden müssen, den folgenden Code verwenden, um die Sperre zu erhalten:

mutex.Lock()
defer mutex.Unlock()
# 🎜🎜#Es ist erwähnenswert, dass Mutex-Sperren keinen Wiedereintritt unterstützen. Wenn eine Coroutine die Sperre bereits erworben hat, führt der Versuch, die Sperre erneut zu erlangen, zu einem Deadlock. Daher verwenden wir normalerweise die Defer-Anweisung, um die Sperre automatisch aufzuheben, wenn die Coroutine endet.

Das Folgende ist ein Beispiel für die Verwendung eines Mutex:

import (
    "fmt"
    "sync"
)

var count = 0
var mutex = &sync.Mutex{}

func increment(wg *sync.WaitGroup) {
    mutex.Lock()
    defer mutex.Unlock()
    count++
    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()
    fmt.Println("Count:", count)
}

In diesem Beispiel verwenden wir einen Mutex, um einen Zähler zu schützen. 1000 Coroutinen führen die Inkrementierungsfunktion gleichzeitig aus und addieren jedes Mal 1 zum Zähler. Durch die Verwendung von Mutex-Sperren kann das Programm den endgültigen Zählerwert korrekt ausgeben.

    Lese-/Schreibsperre
In einer Umgebung mit mehreren Coroutinen ist die Lese-/Schreibsperre (Read-Write Lock) möglicherweise besser als Mutex sperren. Im Gegensatz dazu kann es effizient bleiben, wenn mehrere Coroutinen gleichzeitig von einer gemeinsam genutzten Ressource lesen, bei Schreibvorgängen ist jedoch immer noch ein sich gegenseitig ausschließender Zugriff erforderlich.

Lese-/Schreibsperren bestehen aus zwei Arten von Sperren: Lesesperren und Schreibsperren. Lesesperren ermöglichen mehreren Coroutinen den gleichzeitigen Zugriff auf gemeinsam genutzte Ressourcen, Schreibsperren stellen jedoch sicher, dass nur eine Coroutine gleichzeitig auf sie zugreifen kann.

In der Go-Sprache können Sie den RWMutex-Typ im Synchronisierungspaket verwenden, um eine Lese-/Schreibsperre zu erstellen.

import "sync"

var rwlock = &sync.RWMutex{}

Die Erfassungsmethoden der Lesesperre und der Schreibsperre sind unterschiedlich. Im Folgenden sind einige häufige Verwendungen aufgeführt:

    Lesesperre erwerben: rwlock.RLock()
  • Lesesperre freigeben: rwlock.RUnlock()
  • # 🎜🎜#Schreibsperre erwerben: rwlock.Lock()
  • Schreibsperre freigeben: rwlock.Unlock()
  • Das Folgende ist ein Beispiel für die Verwendung von Lese- Schreibsperre:
import (
    "fmt"
    "sync"
)

var count = 0
var rwlock = &sync.RWMutex{}

func increment(wg *sync.WaitGroup) {
    rwlock.Lock()
    defer rwlock.Unlock()
    count++
    wg.Done()
}

func read(wg *sync.WaitGroup) {
    rwlock.RLock()
    defer rwlock.RUnlock()
    fmt.Println("Count:", count)
    wg.Done()
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go read(&wg)
    }
    wg.Wait()
}

In diesem Beispiel haben wir gleichzeitig 10 Coroutinen geöffnet, um Daten in den Zähler zu schreiben, und 5 Coroutinen, um die Zählerdaten zu lesen. Durch die Verwendung von Lese-/Schreibsperren können Programme gemeinsam genutzte Ressourcen auf effiziente Weise lesen und gleichzeitig die Atomizität von Schreibvorgängen sicherstellen.

Atomoperationen
  1. In der Go-Sprache können Sie auch atomare Operationen verwenden, um sicherzustellen, dass die Operation von Synchronisationsprimitiven atomar ist. Atomare Operationen erfordern keine Sperren und sind daher in manchen Situationen effizienter als Sperren.

Die Go-Sprache verfügt über mehrere integrierte atomare Operationsfunktionen. Sie können sich auf die offizielle Dokumentation beziehen. Hier sind zwei häufig verwendete atomare Operationsfunktionen: atomic.Add und atomic.Load.

atomic.Add: Führt eine atomare Additionsoperation für eine Ganzzahl durch.
  • atomic.Load: Den Wert einer Ganzzahl atomar lesen.
  • Das Folgende ist ein Beispiel:
import (
    "fmt"
    "sync/atomic"
    "time"
)

var count int32 = 0

func increment(wg *sync.WaitGroup) {
    defer wg.Done()
    atomic.AddInt32(&count, 1)
}

func printCount() {
    fmt.Println("Count: ", atomic.LoadInt32(&count))
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()
    printCount()

    time.Sleep(time.Second)

    for i := 0; i < 3; i++ {
        wg.Add(1)
        go increment(&wg)
    }
    wg.Wait()
    printCount()
}

In diesem Beispiel verwenden wir die Funktion atomic.Add, um atomare Additionsoperationen am Zähler und am atomaren durchzuführen .Funktion atomar laden. Den Zählerwert manuell lesen. Durch die Verwendung atomarer Operationen können wir den Overhead von Sperren vermeiden und eine effizientere gleichzeitige Programmierung erreichen.

Zusammenfassung
  1. Die Go-Sprache bietet eine Vielzahl von Synchronisationsmechanismen, einschließlich Mutex-Sperren, Lese-/Schreibsperren und atomaren Operationen. Der Einsatz geeigneter Synchronisationsmechanismen bei der gleichzeitigen Programmierung ist der Schlüssel zur Gewährleistung einer korrekten und effizienten Ausführung von Programmen. Um Deadlocks zu vermeiden, müssen wir sorgfältig darüber nachdenken, welcher Sperrmechanismus für die aktuell gemeinsam genutzten Ressourcen am besten geeignet ist. In der Go-Sprache ist die Verwendung von Sperren sehr einfach. Es ist zu beachten, dass die Haltezeit der Sperre so weit wie möglich reduziert werden sollte, um die Leistung des Programms nicht zu beeinträchtigen.

Das obige ist der detaillierte Inhalt vonWie verwende ich Sperren in Go?. 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