Maison  >  Article  >  développement back-end  >  Comment utiliser les verrous dans Go ?

Comment utiliser les verrous dans Go ?

PHPz
PHPzoriginal
2023-05-11 15:33:062446parcourir

En programmation concurrente, le verrouillage est un mécanisme utilisé pour protéger les ressources partagées. Dans le langage Go, les verrous sont l'un des outils importants pour parvenir à la concurrence. Il garantit que lorsque plusieurs coroutines accèdent simultanément aux ressources partagées, une seule coroutine peut lire ou modifier ces ressources. Cet article présentera l'utilisation des verrous en langage Go pour aider les lecteurs à mieux comprendre la programmation simultanée.

  1. Mutual Exclusion Lock

Mutual Exclusion Lock est le mécanisme de verrouillage le plus couramment utilisé dans le langage Go. Cela garantit qu’une seule coroutine peut accéder à la section critique en même temps. En termes simples, un verrou mutex garantit qu'une seule coroutine peut y accéder en même temps en encapsulant la ressource partagée dans la section critique du verrouillage.

Utiliser les verrous mutex en langage Go est très simple. Nous pouvons utiliser le type Mutex dans le package de synchronisation pour créer un verrou mutex :

import "sync"

var mutex = &sync.Mutex{}

Après cela, à l'emplacement où les ressources partagées doivent être protégées, nous pouvons utiliser le code suivant pour obtenir le verrou :

mutex.Lock()
defer mutex.Unlock()
# 🎜🎜#Il convient de noter que les verrous mutex ne prennent pas en charge la réentrée. Si une coroutine a déjà acquis le verrou, tenter à nouveau d’acquérir le verrou entraînera un blocage. Par conséquent, nous utilisons généralement l'instruction defer pour libérer automatiquement le verrou à la fin de la coroutine.

Ce qui suit est un exemple d'utilisation d'un 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)
}

Dans cet exemple, nous utilisons un mutex pour protéger un compteur. 1 000 coroutines exécutent la fonction d'incrémentation en même temps, en ajoutant 1 au compteur à chaque fois. Grâce à l'utilisation de verrous mutex, le programme peut afficher correctement la valeur finale du compteur.

    Read-Write Lock
Dans un environnement multi-coroutines, le verrouillage en lecture-écriture (Read-Write Lock) peut être meilleur que le mutex verrouillage. En revanche, il peut rester efficace lorsque plusieurs coroutines lisent simultanément une ressource partagée, mais nécessite toujours un accès mutuellement exclusif lorsqu'il y a des opérations d'écriture.

Les verrous en lecture-écriture se composent de deux types de verrous : les verrous en lecture et les verrous en écriture. Les verrous en lecture permettent à plusieurs coroutines d'accéder aux ressources partagées en même temps, mais les verrous en écriture garantissent qu'une seule coroutine peut y accéder en même temps.

En langage Go, vous pouvez utiliser le type RWMutex dans le package de synchronisation pour créer un verrou en lecture-écriture.

import "sync"

var rwlock = &sync.RWMutex{}

Les méthodes d'acquisition du verrouillage en lecture et du verrouillage en écriture sont différentes. Voici quelques utilisations courantes :

    Acquérir le verrou en lecture : rwlock.RLock()
  • Libérer le verrou en lecture : rwlock.RUnlock()
  • # 🎜🎜#Acquérir le verrou en écriture : rwlock.Lock()
  • Libérer le verrou en écriture : rwlock.Unlock()
  • Ce qui suit est un exemple d'utilisation de la lecture write lock :
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()
}

Dans cet exemple, nous avons ouvert simultanément 10 coroutines pour écrire des données sur le compteur et 5 coroutines pour lire les données du compteur. En utilisant des verrous en lecture-écriture, les programmes peuvent lire les ressources partagées de manière efficace tout en garantissant l'atomicité des opérations d'écriture.

Opérations atomiques
  1. En langage Go, vous pouvez également utiliser des opérations atomiques pour vous assurer que le fonctionnement des primitives de synchronisation est atomique. Les opérations atomiques ne nécessitent pas de verrouillage et sont donc plus efficaces que les verrous dans certaines situations.

Le langage Go a plusieurs fonctions d'opération atomique intégrées, vous pouvez vous référer à la documentation officielle. Voici deux fonctions d’opération atomique couramment utilisées : atomic.Add et atomic.Load.

atomic.Add : effectue une opération d'addition atomique sur un entier.
  • atomic.Load : Lit la valeur d'un entier de manière atomique.
  • Ce qui suit est un exemple :
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()
}

Dans cet exemple, nous utilisons la fonction atomic.Add pour effectuer des opérations d'addition atomique sur le compteur, et l'atomique .Load fonction atomiquement Lire la valeur du compteur manuellement. En utilisant des opérations atomiques, nous pouvons éviter la surcharge des verrous et obtenir une programmation simultanée plus efficace.

Summary
  1. Le langage Go fournit une variété de mécanismes de synchronisation, notamment des verrous mutex, des verrous en lecture-écriture et des opérations atomiques. L'utilisation de mécanismes de synchronisation appropriés dans la programmation simultanée est essentielle pour garantir que les programmes fonctionnent correctement et efficacement. Afin d'éviter une impasse, nous devons soigneusement réfléchir au mécanisme de verrouillage le plus adapté aux ressources partagées actuelles. En langage Go, la manière d’utiliser les verrous est très simple. Il convient de noter que le temps de maintien du verrou doit être réduit autant que possible pour éviter de réduire les performances du programme.

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