Mécanisme de synchronisation et solution d'optimisation des goulots d'étranglement des performances dans Golang
package main import ( "fmt" "sync" ) var ( count int lock sync.Mutex ) func increment() { lock.Lock() defer lock.Unlock() count++ } func main() { var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go func() { defer wg.Done() increment() }() } wg.Wait() fmt.Println(count) }
2.2 Variable de condition (Cond)
Les variables de condition sont utilisées pour communiquer entre les coroutines et implémenter le mécanisme d'attente et de réveil des coroutines. Lorsqu'une coroutine remplit certaines conditions, vous pouvez utiliser des variables de condition pour notifier d'autres coroutines. Voici un exemple de code utilisant des variables de condition :
package main import ( "fmt" "sync" ) var ( ready bool cond *sync.Cond ) func init() { cond = sync.NewCond(&sync.Mutex{}) } func printNumbers() { cond.L.Lock() defer cond.L.Unlock() for !ready { cond.Wait() } fmt.Println("1 2 3 4 5") } func main() { go printNumbers() cond.L.Lock() ready = true cond.Signal() cond.L.Unlock() }
2.3 Verrouillage en lecture-écriture (RWMutex)
Le verrouillage en lecture-écriture peut améliorer encore les performances des programmes simultanés. Dans les scénarios où il y a beaucoup de lectures et peu d'écritures, l'utilisation de verrous en lecture-écriture peut permettre à plusieurs coroutines de lire des ressources partagées en même temps, tandis qu'une seule coroutine peut effectuer des opérations d'écriture. Voici un exemple de code utilisant un verrou en lecture-écriture :
package main import ( "fmt" "sync" ) var ( count int lock sync.RWMutex ) func read() { lock.RLock() defer lock.RUnlock() fmt.Println(count) } func write() { lock.Lock() defer lock.Unlock() count++ } func main() { var wg sync.WaitGroup wg.Add(10) for i := 0; i < 5; i++ { go func() { defer wg.Done() read() }() go func() { defer wg.Done() write() }() } wg.Wait() }
3.1 Réduire la granularité du verrouillage
Lorsque vous utilisez un verrouillage mutex, vous pouvez réduire la granularité du verrouillage autant que possible et verrouiller uniquement les segments de code de section critiques nécessaires. Cela réduit les conflits de verrouillage. Lorsque vous utilisez un verrou en lecture-écriture, vous pouvez choisir un verrou en lecture ou un verrou en écriture en fonction de la situation réelle pour exploiter pleinement les caractéristiques de la lecture parallèle.
3.2 Utiliser des structures de données sans verrouillage
Pour les scénarios à forte concurrence, vous pouvez envisager d'utiliser des structures de données sans verrouillage, telles que les fonctions d'opération atomiques du package atomique. Ces fonctions fournissent certaines opérations atomiques sans utiliser de verrous pour garantir la cohérence des données. Par exemple, utilisez atomic.AddInt64() au lieu d'un mutex pour garantir un comptage cohérent.
3.3 Utiliser des canaux au lieu de verrous mutex
Les canaux peuvent être utilisés comme mécanisme de synchronisation pour garantir l'ordre et la cohérence de l'accès aux données. Dans certains scénarios, l'utilisation de canaux peut éviter l'utilisation explicite de verrous mutex, réduisant ainsi les conflits de verrouillage. Cependant, il faut prêter attention à la capacité du canal et à la surcharge de performances pour éviter les blocages ou les fuites de mémoire.
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!