Maison >développement back-end >Golang >Un article expliquant en détail le mécanisme de verrouillage en langage Go

Un article expliquant en détail le mécanisme de verrouillage en langage Go

PHPz
PHPzoriginal
2023-04-13 18:12:031679parcourir

En tant que langage de programmation hautement concurrentiel, le mécanisme de contrôle de concurrence du langage Go est très important. L’un des mécanismes les plus couramment utilisés est le mécanisme de verrouillage. Cet article présentera comment implémenter le mécanisme de verrouillage en langage Go.

Verrous du langage Go

Dans le langage Go, le verrou le plus couramment utilisé est le verrou mutex (Mutex). Un mutex est un sémaphore binaire spécial utilisé pour contrôler l'accès aux ressources partagées. Le langage Go fournit la fonction de verrouillage mutex via le package "sync" de la bibliothèque standard. Le type de verrou mutex est défini comme suit :

type Mutex struct {
    state int32
    sema  uint32
}

Le champ state est utilisé pour enregistrer l'état du verrou, et le champ sema est un sémaphore.

Avant d'utiliser un verrou mutex, vous devez obtenir le verrou en appelant la méthode Lock. Si le verrou est déjà détenu par une autre coroutine, la coroutine actuelle sera bloquée, en attendant que le verrou soit libéré. Par exemple :

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

Dans ce code, mu est un verrou mutex. mu.Lock() est utilisé pour acquérir le verrou. Si le verrou est déjà détenu par une autre coroutine, la coroutine actuelle sera bloquée. mu.Unlock() est utilisé pour libérer le verrou. 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()

Ce mécanisme est très simple, mais en fait il n'est pas très efficace. Si de nombreuses coroutines tentent d'acquérir le même mutex, une congestion se produira facilement pendant le traitement, réduisant ainsi l'efficacité de l'ensemble du programme.

Verrouillage en lecture-écriture

Dans certains scénarios nécessitant des opérations de lecture et d'écriture, l'efficacité des verrous mutex est très faible. Étant donné que le verrou mutex ne peut garantir qu'une seule coroutine peut accéder à la ressource partagée en même temps, les opérations de lecture et d'écriture doivent d'abord attendre que le verrou soit libéré. Toutefois, s'il n'y a que des opérations de lecture, cette attente n'est pas nécessaire. Parce que plusieurs coroutines peuvent lire la même ressource en même temps sans provoquer de modifications destructrices des données.

À ce stade, vous devez utiliser le verrou en lecture-écriture (RWMutex). Le verrouillage en lecture-écriture est un type particulier de verrouillage d'exclusion mutuelle. Une ressource peut être lue par plusieurs coroutines en même temps, mais ne peut être écrite que par une seule coroutine. Par conséquent, lors d’une opération d’écriture, toutes les opérations de lecture seront bloquées, en attendant la fin de l’opération d’écriture. Les types de verrous en lecture-écriture sont définis comme suit :

func singleton() {
    var once sync.Once
    once.Do(func() {
        // 初始化对象
    })
    // 使用对象
}
Les verrous en lecture-écriture ont deux états : le verrouillage en lecture et le verrouillage en écriture. Dans l'état de verrouillage en lecture, plusieurs coroutines peuvent effectuer des opérations de lecture en même temps ; dans l'état de verrouillage en écriture, une seule coroutine peut effectuer des opérations d'écriture. Dans le même temps, les verrous en lecture-écriture prennent en charge le mécanisme de priorité des coroutines, ce qui signifie que la coroutine qui attend le plus obtiendra le verrou en premier.

La méthode pour acquérir le verrou en lecture est RLock(), la méthode pour libérer le verrou en lecture est RUnlock() ; >Lock()code>, la méthode pour libérer le verrou en écriture est Unlock(). Par exemple : 🎜rrreee🎜Ce code montre comment utiliser les verrous en lecture-écriture dans le langage Go. La fonction read() acquiert un verrou en lecture et peut être appelée par plusieurs coroutines en même temps tandis que la fonction write() acquiert un verrou en écriture et ne peut en avoir qu'un seul ; en même temps. La coroutine l'appelle. 🎜🎜sync.Once🎜🎜sync.Once est un verrou très utile. Il n’effectue l’opération d’initialisation qu’une seule fois. Il y a une valeur booléenne à l'intérieur de Once. S'il est verrouillé, une fois l'appel échoué, les appels suivants reviendront immédiatement et l'initialisation ne sera pas réexécutée. 🎜rrreee🎜L'utilisation de sync.Once peut éviter des opérations d'initialisation répétées dans plusieurs coroutines. 🎜🎜Résumé🎜🎜Dans le langage Go, le mécanisme permettant d'implémenter le contrôle de concurrence multi-thread est très important. En utilisant des mécanismes tels que les verrous mutex, les verrous en lecture-écriture et Once, le programme peut devenir plus efficace et plus sûr lors de la gestion d'opérations simultanées. En pratique, divers mécanismes doivent être sélectionnés en fonction de scénarios spécifiques, et certains tests et vérifications doivent être effectués avant la sélection et l'utilisation. 🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:Comment tester avec GolangArticle suivant:Comment tester avec Golang