Maison  >  Article  >  développement back-end  >  Le remplacement d'une variable mappée par un nouvel objet mappé est-il thread-safe ?

Le remplacement d'une variable mappée par un nouvel objet mappé est-il thread-safe ?

WBOY
WBOYavant
2024-02-10 16:33:12864parcourir

Le remplacement dune variable mappée par un nouvel objet mappé est-il thread-safe ?

Éditeur PHP Apple est là pour répondre à une question courante : « Est-il thread-safe de remplacer une variable de mappage par un nouvel objet de mappage ? » Une variable de mappage est une structure de données courante utilisée pour stocker des paires clé-valeur. Dans un environnement multithread, la sécurité des threads est une considération importante. Bien que l'utilisation d'un nouvel objet de mappage puisse éviter le problème de l'accès simultané, sa compatibilité avec les threads doit encore être évaluée au cas par cas. Ensuite, nous explorerons cette question en profondeur pour aider les lecteurs à mieux comprendre la relation entre la sécurité des threads et les objets mappés.

Contenu de la question

Je ne pense pas qu'il soit thread-safe car l'objet mappé est plus grand que les mots machine et golang ne garantit pas qu'il est thread-safe. Mais lorsque j'exécute le code de démonstration en utilisant go run -race main.go, il ne signale jamais d'erreur. C'est peut-être la raison pour laquelle threadsanitizer s'appuie sur des contrôles d'exécution et des opérations d'affectation pour avoir du mal à satisfaire des conditions non sécurisées pour les threads.

Voici l'exemple de code :

package main

import (
    "fmt"
)

var m = make(map[int]bool)

func Read() {
    for {
        for k := range m {
            fmt.Println(k)
        }
    }
}

func Replace() {
    for {
        newM := make(map[int]bool, 10)
        for i := 0; i < 10; i++ {
            newM[i] = false
        }
        m = newM
    }
}

func main() {
    c := make(chan struct{})

    go Read()
    go Replace()

    <-c
}

Alors, comment modifier le code pour déclencher des erreurs de concurrence ? Ou peut-être que je me trompe et que le code est thread-safe ?

Solution

Voici quelques points à noter :

for k := range m {

Les expressions Range sont évaluées une fois au début de la boucle for. Cette opération lira donc m 一次(注意,这意味着如果循环中的代码重新分配 m ,则循环将继续迭代原始 m ,但是如果添加新元素或从 m 中删除元素,这些将被检测到循环),循环本身会调用 fmt.println , ce qui consommera la majeure partie du temps d'exécution dans cette goroutine. Si vous souhaitez rattraper le jeu, supprimez-le.

Deuxièmement, vous n'avez pas réellement besoin d'initialiser la deuxième carte.

Lorsque vous effectuez ces opérations et exécutez le détecteur de course, il peut détecter des courses de données. En ce qui me concerne, c'est le cas.

Le détecteur de conflits se plaindra d'un conflit lorsqu'il le détectera. Donc, s’il signale une correspondance, alors il y a une correspondance. Si ce n’est pas signalé, cela ne veut pas dire qu’il n’y a pas de contestation.

Sur ma plateforme, la variable map elle-même a en fait la même taille qu'un mot machine : c'est juste un pointeur vers la structure mappée. Par conséquent, les écritures sur les variables mappées sont effectivement atomiques, c'est-à-dire que vous ne verrez pas de mappages partiellement alloués sur cette plateforme. Cependant, cela n'empêche pas les conflits puisqu'il n'y a aucune garantie quand d'autres goroutines verront cette mémoire écrire.

En bref, c’est une compétition. Cela n'est pas dû à la taille de la variable map. Pour résoudre ce problème, utilisez un mutex.

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:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer