Synchronisation de carte synchrone de Golang

La carte de type de dictionnaire fournie avec Go n'est pas simultanément sûre.

Dans Go 1.9, le type de dictionnaire simultanément sécurisé sync.Map a été officiellement ajouté.

Ce type de dictionnaire fournit des méthodes d'opération d'accès aux valeurs clés couramment utilisées et garantit la sécurité simultanée de ces opérations. Dans le même temps, ses opérations de sauvegarde, d'extraction, de suppression, etc. peuvent être fondamentalement garanties d'être achevées dans un temps constant. En d'autres termes, leur complexité algorithmique est O (1) comme le type de carte.

Dans certains cas, l'utilisation de sync.Map peut réduire considérablement les conflits de verrouillage par rapport aux schémas de verrouillage de carte et de mutex purement natifs. Bien que sync.Map lui-même utilise également des verrous, il évite en fait d'utiliser des verrous autant que possible.

Nous savons tous que l'utilisation de verrous signifie que certaines opérations simultanées doivent être forcées de sérialiser. Cela réduit souvent les performances du programme, en particulier si l'ordinateur possède plusieurs cœurs de processeur. Par conséquent, nous disons souvent que vous pouvez utiliser des opérations atomiques sans utiliser de verrous, mais cela est très limité. Après tout, les atomes ne peuvent prendre en charge que certains types de données de base .

Peu importe le type de scénario que vous utilisez sync.Map, nous devons noter qu'il est évidemment différent de la carte native. Ce n'est qu'un membre de la bibliothèque standard de langue Go, pas une chose de niveau de langue. Pour cette raison, le compilateur de langage Go n'effectue pas de vérification de type spécial sur ses clés et ses valeurs.

Les types de clés et de valeurs impliqués dans toutes les méthodes de sync.Map sont l'interface {}, qui est une interface vide, ce qui signifie que tout peut être couvert. Par conséquent, nous devons garantir l'exactitude de son type de clé et de son type de valeur dans le programme.

Les dictionnaires de sécurité simultanés nécessitent-ils des types de clés?

Il y a des exigences. Les types réels de touches ne peuvent pas être des types de fonction, des types de dictionnaire et des types de tranche.

Les types clés des dictionnaires natifs de Go ne peuvent pas être des types de fonction, des types de dictionnaire et des types de tranche.

Étant donné que le support de stockage utilisé dans le dictionnaire de sécurité simultané est le dictionnaire natif et que le type de clé de dictionnaire natif qu'il utilise est également une interface globale {}; par conséquent, nous ne devons prendre aucun type réel comme type de fonction, type de dictionnaire ou type de tranche Valeur de clé pour utiliser le dictionnaire de sécurité simultané.

Étant donné que les types réels de ces valeurs de clé ne peuvent être déterminés que pendant l'exécution du programme, le compilateur de langage Go ne peut pas les vérifier au moment de la compilation. Les types réels de valeurs de clé incorrectes provoqueront certainement une panique. Par conséquent, la première chose que nous devons faire ici est: ne violez pas les règles ci-dessus. Nous devons vérifier explicitement le type réel de valeur de clé chaque fois que nous opérons sur un dictionnaire de sécurité simultané. Cela devrait être vrai que ce soit pour enregistrer, récupérer ou supprimer .

Collectez toutes ces opérations pour le même dictionnaire de sécurité simultané, puis écrivez le code d'inspection de manière unifiée. En outre, l'encapsulation du dictionnaire de sécurité simultané dans un type de structure est souvent un bon choix.

Nous devons nous assurer que les types de clés sont comparables (ou vérifiables). Si vous n'êtes pas sûr, vous pouvez d'abord obtenir la valeur de type de réflexion correspondant à une valeur de clé en appelant la fonction reflect.TypeOf (c'est-à-dire: valeur de type reflect.Type), puis appeler la méthode comparable de cette valeur pour obtenir le résultat de jugement exact .

Comment garantir le bon type de clés et de valeurs dans le dictionnaire de sécurité simultané?

En termes simples, vous pouvez utiliser des expressions d'assertion de type ou des opérations de réflexion pour garantir leur exactitude.

La première solution consiste à ne stocker dans le dictionnaire de sécurité simultané qu'un certain type de clé. Applicable à la situation où nous pouvons déterminer complètement les types spécifiques de clés et de valeurs . Par exemple, la clé spécifiée ici ne peut être que de type int ou ne peut être qu'une chaîne ou un certain type de structure. Une fois que le type de la clé est complètement déterminé, vous pouvez utiliser l'expression d'assertion de type pour vérifier le type de la clé lors de l'exécution des opérations d'enregistrement, de récupération et de suppression. En général, ce contrôle n'est pas lourd. De plus, il est plus pratique si vous encapsulez le dictionnaire de sécurité simultané dans un type de structure. Vous pouvez maintenant laisser le compilateur de langue Go vous aider à effectuer la vérification de type. Le code est le suivant:

type IntStrMap struct {
 m sync.Map
}

func (iMap *IntStrMap) Delete(key int) {
 iMap.m.Delete(key)
}

func (iMap *IntStrMap) Load(key int) (value string, ok bool) {
 v, ok := iMap.m.Load(key)
 if v != nil {
  value = v.(string)
 }
 return
}

func (iMap *IntStrMap) LoadOrStore(key int, value string) (actual string, loaded bool) {
 a, loaded := iMap.m.LoadOrStore(key, value)
 actual = a.(string)
 return
}

func (iMap *IntStrMap) Range(f func(key int, value string) bool) {
 f1 := func(key, value interface{}) bool {
  return f(key.(int), value.(string))
 }
 iMap.m.Range(f1)
}

func (iMap *IntStrMap) Store(key int, value string) {
 iMap.m.Store(key, value)
}

Un type de structure nommé IntStrMap a été écrit, qui représente un dictionnaire de sécurité simultané avec un type de clé int et un type valeur de chaîne. Dans ce type de structure, il n'y a qu'un seul champ m de type sync.Map. Et, toutes les méthodes de ce type sont très similaires aux méthodes du type sync.Map.

Les noms de méthode correspondants sont exactement les mêmes et les signatures de méthode sont très similaires, sauf que les types des paramètres et des résultats liés aux clés et aux valeurs sont différents. Dans la signature de méthode du type IntStrMap, il est clair que le type de la clé est int et le type de la valeur est string.

 

Si nous voulons conserver la flexibilité d'origine du type sync.Map, nous voulons également contraindre les types de clés et de valeurs.

Solution 2: toutes les méthodes du type de structure encapsulée peuvent être totalement cohérentes avec les méthodes du type sync.Map (y compris le nom de la méthode et la signature de la méthode) .

Nous devons ajouter du code pour effectuer une vérification de type.

Le type de clé et le type de valeur doivent être complètement déterminés au moment de l'initialisation et les types de clés sont comparables.

type ConcurrentMap struct {
 m         sync.Map
 keyType   reflect.Type
 valueType reflect.Type
}

 

 

 

 

 

 

 

A publié 127 articles originaux · Aime 24 · Visites 130 000+

Je suppose que tu aimes

Origine blog.csdn.net/Linzhongyilisha/article/details/105473092
conseillé
Classement