Heim  >  Artikel  >  Backend-Entwicklung  >  Ein Artikel, der den Sperrmechanismus in der Go-Sprache ausführlich erklärt

Ein Artikel, der den Sperrmechanismus in der Go-Sprache ausführlich erklärt

PHPz
PHPzOriginal
2023-04-13 18:12:031651Durchsuche

Als Programmiersprache mit hoher Parallelität ist der Parallelitätskontrollmechanismus der Go-Sprache sehr wichtig. Einer der am häufigsten verwendeten Mechanismen ist der Sperrmechanismus. In diesem Artikel wird erläutert, wie der Sperrmechanismus in der Go-Sprache implementiert wird.

Go-Sprachsperren

In der Go-Sprache ist die am häufigsten verwendete Sperre die Mutex-Sperre (Mutex). Ein Mutex ist ein spezielles binäres Semaphor, das zur Steuerung des Zugriffs auf gemeinsam genutzte Ressourcen verwendet wird. Die Go-Sprache stellt die Mutex-Sperrfunktion über das „sync“-Paket in der Standardbibliothek bereit. Der Typ der Mutex-Sperre ist wie folgt definiert:

type Mutex struct {
    state int32
    sema  uint32
}

Das Statusfeld wird zum Aufzeichnen des Status der Sperre verwendet, und das Sema-Feld ist ein Semaphor.

Bevor Sie eine Mutex-Sperre verwenden, müssen Sie die Sperre durch Aufrufen der Lock-Methode erhalten. Wenn die Sperre bereits von einer anderen Coroutine gehalten wird, wird die aktuelle Coroutine blockiert und wartet auf die Freigabe der Sperre. Zum Beispiel:

var mu sync.Mutex
// ...
mu.Lock()
// ...
mu.Unlock()

In diesem Code ist mu eine Mutex-Sperre. mu.Lock() wird zum Erlangen der Sperre verwendet. Wenn die Sperre bereits von einer anderen Coroutine gehalten wird, wird die aktuelle Coroutine blockiert. mu.Unlock() wird verwendet, um die Sperre aufzuheben. mu是一个互斥锁。mu.Lock()用于获取锁,如果锁已经被其他协程持有,则当前协程将会被阻塞。mu.Unlock()用于释放锁。

这个机制非常简单,但实际上效率并不高。如果有很多协程试图获取同一个互斥锁,那么处理时就很容易产生拥塞,从而使得整个程序的效率降低。

读写锁

在一些需要进行读写操作的场景下,互斥锁的效率很低。因为互斥锁只能保证在同一时刻只有一个协程能够访问共享资源,读操作和写操作都需要先等待锁的释放。但是,如果只有读操作,则这种等待并没有必要。因为多个协程可以同时对同一个资源进行读操作,而不会对数据产生破坏性的修改。

这时候就需要用到读写锁(RWMutex)。读写锁是一种特殊的互斥锁。一个资源可以被多个协程同时进行读操作,但只能被一个协程进行写操作。因此,在写操作时,所有读操作将会被阻塞,等待写操作结束。读写锁的类型定义如下:

type RWMutex struct {
    w           Mutex // 用于写操作的互斥锁
    writerSem   uint32
    readerSem   uint32
    readerCount int32  // 当前进行读操作的协程数量
    readerWait  int32  // 等待读操作的协程数量
}

读写锁有两种状态:读锁和写锁。读锁状态下,多个协程可以同时进行读操作;写锁状态下,只有一个协程可以进行写操作。同时,读写锁支持协程优先级的机制,这意味着等待时间更长的协程将会首先获取到锁。

获取读锁的方法是RLock(),释放读锁的方法是RUnlock();获取写锁的方法是Lock(),释放写锁的方法是Unlock()。举个例子:

var rw sync.RWMutex
// ...
func read() {
    rw.RLock()
    // ...
    rw.RUnlock()
}
// ...
func write() {
    rw.Lock()
    // ...
    rw.Unlock()
}

这段代码演示了如何在Go语言中使用读写锁。read()函数获取了读锁,同时可以被多个协程同时调用;而write()

Dieser Mechanismus ist sehr einfach, aber tatsächlich nicht sehr effizient. Wenn viele Coroutinen versuchen, denselben Mutex zu erhalten, kommt es während der Verarbeitung leicht zu einer Überlastung, wodurch die Effizienz des gesamten Programms verringert wird.

Lese-/Schreibsperre

In einigen Szenarien, in denen Lese- und Schreibvorgänge erforderlich sind, ist die Effizienz von Mutex-Sperren sehr gering. Da die Mutex-Sperre nur garantieren kann, dass nur eine Coroutine gleichzeitig auf die gemeinsam genutzte Ressource zugreifen kann, müssen sowohl Lese- als auch Schreibvorgänge zunächst auf die Freigabe der Sperre warten. Wenn es sich jedoch nur um Lesevorgänge handelt, ist diese Wartezeit nicht erforderlich. Weil mehrere Coroutinen gleichzeitig dieselbe Ressource lesen können, ohne destruktive Änderungen an den Daten zu verursachen.

Zu diesem Zeitpunkt müssen Sie die Lese-/Schreibsperre (RWMutex) verwenden. Die Lese-/Schreibsperre ist eine besondere Art der gegenseitigen Ausschlusssperre. Eine Ressource kann von mehreren Coroutinen gleichzeitig gelesen, aber nur von einer Coroutine geschrieben werden. Daher werden während eines Schreibvorgangs alle Lesevorgänge blockiert und auf den Abschluss des Schreibvorgangs gewartet. Die Arten von Lese-/Schreibsperren sind wie folgt definiert:

func singleton() {
    var once sync.Once
    once.Do(func() {
        // 初始化对象
    })
    // 使用对象
}
Lese-/Schreibsperren haben zwei Zustände: Lesesperre und Schreibsperre. Im Lesesperrzustand können mehrere Coroutinen gleichzeitig Lesevorgänge ausführen; im Schreibsperrzustand kann nur eine Coroutine Schreibvorgänge ausführen. Gleichzeitig unterstützen Lese-/Schreibsperren den Coroutine-Prioritätsmechanismus, was bedeutet, dass Coroutinen, die länger warten, die Sperre zuerst erhalten.

Die Methode zum Erlangen der Lesesperre ist RLock(), die Methode zum Aufheben der Lesesperre ist RUnlock(); die Methode zum Erlangen der Schreibsperre ist Lock()code>, die Methode zum Aufheben der Schreibsperre ist Unlock(). Zum Beispiel: 🎜rrreee🎜Dieser Code zeigt, wie Lese-/Schreibsperren in der Go-Sprache verwendet werden. Die Funktion read() erhält eine Lesesperre und kann von mehreren Coroutinen gleichzeitig aufgerufen werden, während die Funktion write() eine Schreibsperre erhält und nur eine haben kann gleichzeitig ruft die Coroutine es auf. 🎜🎜sync.Once🎜🎜sync.Once ist eine sehr nützliche Sperre. Der Initialisierungsvorgang wird nur einmal durchgeführt. In Once befindet sich ein boolescher Wert. Wenn der Aufruf fehlschlägt, werden nachfolgende Aufrufe sofort zurückgegeben und die Initialisierung wird nicht erneut ausgeführt. 🎜rrreee🎜Durch die Verwendung von sync.Once können wiederholte Initialisierungsvorgänge in mehreren Coroutinen vermieden werden. 🎜🎜Zusammenfassung🎜🎜In der Go-Sprache ist der Mechanismus zur Implementierung der Multithread-Parallelitätskontrolle sehr wichtig. Durch die Verwendung von Mechanismen wie Mutex-Sperren, Lese-/Schreibsperren und Once kann das Programm bei der Verarbeitung gleichzeitiger Vorgänge effizienter und sicherer werden. In der Praxis müssen je nach Szenario verschiedene Mechanismen ausgewählt und vor der Auswahl und Verwendung bestimmte Tests und Überprüfungen durchgeführt werden. 🎜

Das obige ist der detaillierte Inhalt vonEin Artikel, der den Sperrmechanismus in der Go-Sprache ausführlich erklärt. 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
Vorheriger Artikel:So testen Sie mit GolangNächster Artikel:So testen Sie mit Golang