Maison  >  Article  >  développement back-end  >  Partage pratique de la synchronisation et de la protection du verrouillage des fonctions Golang

Partage pratique de la synchronisation et de la protection du verrouillage des fonctions Golang

WBOY
WBOYoriginal
2023-05-16 09:04:571628parcourir

Avec le développement d'Internet et la vulgarisation du cloud computing et de la technologie du big data, les systèmes logiciels modernes doivent traiter de plus en plus de données, et en même temps, ils doivent également garantir l'efficacité et la fiabilité du système. . Dans ce contexte, les performances et les caractéristiques techniques du langage deviennent particulièrement importantes. Parmi eux, Golang, en tant que langage de programmation efficace, léger et hautement simultané, a reçu de plus en plus d'attention et d'applications ces dernières années. Cet article discutera des pratiques de synchronisation et de protection contre le verrouillage des fonctions Golang et fournira un partage d'expérience utile pour les développeurs Golang.

  1. Les principes et méthodes de synchronisation

La synchronisation est la clé de la collaboration entre plusieurs threads ou processus. Son objectif principal est d'assurer divers corrects. accès et protection des ressources. Dans Golang, les principales méthodes de synchronisation sont les suivantes :

1.1 Verrouillage Mutex (sync.Mutex)

Le verrouillage Mutex est le mécanisme de synchronisation le plus basique de Golang. Son rôle principal est de garantir qu'une seule goroutine puisse accéder aux ressources partagées en même temps. Lorsqu'une goroutine demandera la ressource, elle tentera d'acquérir le verrou. Si elle ne peut pas l'obtenir, elle sera bloquée jusqu'à ce que le verrou soit libéré. Voici un exemple d'implémentation simple d'un mutex :

package main

import (
    "fmt"
    "sync"
)

var count int
var mu sync.Mutex // 互斥锁

func main() {
    for i := 0; i < 10; i++ {
        go increase()
    }

    // 等待所有goroutine执行完成
    for {
        mu.Lock()
        if count == 10 {
            mu.Unlock()
            break
        }
        mu.Unlock()
    }

    fmt.Println("count:", count)
}

func increase() {
    mu.Lock()
    defer mu.Unlock()
    count += 1
}

Dans l'exemple ci-dessus, nous utilisons un mutex pour assurer le fonctionnement atomique du nombre de variables partagées. À l'intérieur de la fonction d'augmentation, nous acquérons d'abord le verrou mutex, puis effectuons une opération d'incrémentation sur le compte, et enfin libérons le verrou. De cette façon, nous pouvons empêcher les accès simultanés au comptage de provoquer des résultats inattendus.

1.2 Verrouillage en lecture-écriture (sync.RWMutex)

RWMutex est un verrou mutex avancé qui prend en charge plusieurs opérations de lecture simultanément, mais n'autorise qu'une seule opération d'écriture. Lors de sa mise en œuvre, il organise les opérations de lecture de plusieurs goroutines en basculant entre les modes de lecture et d'écriture, améliorant ainsi les performances de concurrence. Voici un exemple d'implémentation simple d'un verrou en lecture-écriture :

package main

import (
    "fmt"
    "sync"
)

var count int
var mu sync.RWMutex // 读写锁

func main() {
    for i := 0; i < 10; i++ {
        go increase()
    }

    // 等待所有goroutine执行完成
    for {
        mu.RLock()
        if count == 10 {
            mu.RUnlock()
            break
        }
        mu.RUnlock()
    }

    fmt.Println("count:", count)
}

func increase() {
    mu.Lock()
    defer mu.Unlock()
    count += 1
}

Dans l'exemple ci-dessus, nous utilisons des verrous en lecture-écriture pour garantir les opérations atomiques du nombre de variables partagées. À l'intérieur de la fonction d'augmentation, nous acquérons d'abord le verrou en écriture du verrou en lecture-écriture, puis effectuons une opération d'incrémentation sur le compte, et enfin libérons le verrou. De cette façon, nous pouvons empêcher les accès simultanés au comptage de provoquer des résultats inattendus.

  1. La pratique de la protection par verrouillage

En plus du mécanisme de synchronisation, Golang propose également certaines pratiques de protection par verrouillage pour garantir l'intégrité des données et sécurité. Ce qui suit est une introduction détaillée à quelques méthodes pratiques :

2.1 Fonctionnement atomique (sync/atomic)

Le fonctionnement atomique est une technologie qui peut assurer la synchronisation des données sans verrouillage. Golang fournit une série de fonctions d'opération atomiques pour implémenter les fonctions de base de synchronisation de la mémoire. Voici un exemple :

package main

import (
    "fmt"
    "sync/atomic"
)

var count int32

func main() {
    for i := 0; i < 10; i++ {
        go increase()
    }

    // 等待所有goroutine执行完成
    for {
        if atomic.LoadInt32(&count) == 10 {
            break
        }
    }

    fmt.Println("count:", count)
}

func increase() {
    atomic.AddInt32(&count, 1)
}

Dans l'exemple ci-dessus, nous utilisons la fonction d'opération atomique atomic.AddInt32() pour garantir que l'opération d'incrémentation de compte est atomique, évitant ainsi les conditions de concurrence. Les données sont anormales. .

2.2 Communication par canal

Channel est un outil de synchronisation important dans Golang. Il garantit l'exactitude des données grâce à la communication entre les goroutines. Le canal est quelque peu similaire à un tube Unix, qui permet à une goroutine d'envoyer un bloc de données à une autre goroutine ou de recevoir un bloc de données. Voici un exemple :

package main

import (
    "fmt"
)

func main() {
    ch := make(chan int)
    go increase(ch)

    // 接收所有增加的值
    count := 0
    for i := 0; i < 10; i++ {
       count += <-ch
    }

    fmt.Println("count:", count)
}

func increase(ch chan int) {
    for i := 0; i < 10; i++ {
       ch <- 1
    }
    close(ch)
}

Dans l'exemple ci-dessus, nous utilisons des canaux pour éviter les conditions de concurrence provoquées par l'accès simultané au nombre de données partagées par plusieurs goroutines. À l'intérieur de la fonction d'augmentation, nous envoyons 10 1 à la fonction principale via le canal pour effectuer l'opération de comptage. À l'intérieur de la fonction principale, nous recevons les données dans le canal via une boucle et les accumulons dans la variable count, évitant ainsi les exceptions de données causées par des conditions de concurrence.

2.3 L'instruction defer de sync.Mutex

Dans Golang, les verrous mutex utilisent souvent l'instruction defer pour garantir la libération correcte du verrou. L'instruction defer est un mécanisme qui provoque l'exécution de l'instruction au retour de la fonction. Elle peut éviter les exceptions du programme causées par l'oubli de libérer le verrou. Voici un exemple :

package main

import (
    "fmt"
    "sync"
)

var count int
var mu sync.Mutex // 互斥锁

func main() {
    for i := 0; i < 10; i++ {
        go increase()
    }

    // 等待所有goroutine执行完成
    for {
        mu.Lock()
        if count == 10 {
            mu.Unlock()
            break
        }
        mu.Unlock()
    }

    fmt.Println("count:", count)
}

func increase() {
    mu.Lock()
    defer mu.Unlock()
    count += 1
}

Dans l'exemple ci-dessus, nous utilisons l'instruction defer pour garantir la libération correcte du verrou mutex. Lorsque la goroutine quitte la fonction d'augmentation, l'instruction defer libère automatiquement le verrou pour garantir que la prochaine fois que le verrou sera acquis, il pourra être exécuté avec succès.

Conclusion

Ce qui précède concerne le partage des pratiques de synchronisation et de protection de verrouillage des fonctions Golang. Grâce à l'application de verrous mutex, de verrous en lecture-écriture, d'opérations atomiques, de communication de canal et d'instructions différées, nous pouvons mieux garantir l'exactitude et la sécurité des données dans la programmation multithread Golang. Que ce soit dans les systèmes de cloud computing à grande échelle, les systèmes distribués ou les systèmes de traitement de données en temps réel, ces technologies de synchronisation et de protection contre le verrouillage revêtent une grande importance.

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