Sobes.tech
Middle+

À quel point est-il sûr de passer des slices à différentes goroutines?

sobes.tech IA

Réponse de l'IA

Transmettre des slices directement à différentes goroutines n’est pas sûr si les goroutines les modifient simultanément sans synchronisation ou si le slice est modifié dans une goroutine après avoir été transmis (par copie de l’en-tête) à une autre.

Raisons de l’insécurité :

  • Tableau de base partagé : Les slices sont des en-têtes (pointeur vers le tableau de base, longueur, capacité) pointant vers un tableau de base commun.
  • Condition de course (Race Condition) : Écrire simultanément dans le même élément du tableau de base ou changer sa taille depuis différentes goroutines entraînera des conditions de course, des résultats imprévisibles et des erreurs.

Méthodes sûres pour travailler avec des slices dans des goroutines :

  1. Passer une copie du slice : Créer une copie complète du slice et la transmettre. C’est sûr, car les goroutines travaillent avec des données séparées.

    // créer une copie complète du slice
    newSlice := make([]int, len(originalSlice))
    copy(newSlice, originalSlice)
    
  2. Utiliser des canaux : Transmettre les éléments du slice ou le slice entier via des canaux. Les canaux assurent la synchronisation et l’isolation des données.

    // transmettre des éléments via un canal
    ch := make(chan int)
    go func() {
        for _, v := range originalSlice {
            ch <- v
        }
        close(ch)
    }()
    
    // transmettre le slice via un canal
    chSlice := make(chan []int)
    go func() {
        chSlice <- originalSlice // transmission par valeur de l’en-tête, mais le canal synchronise
                                // important : ne pas modifier originalSlice après l’envoi
    }()
    
  3. Synchronisation avec sync.Mutex ou sync.RWMutex : Protéger l’accès au slice avec des mutex. Cela garantit qu’une seule goroutine peut modifier le slice à tout moment.

    import "sync"
    
    var mu sync.Mutex
    var sharedSlice []int
    
    func modifySlice(index, value int) {
        mu.Lock()
        defer mu.Unlock()
        if index < len(sharedSlice) {
            sharedSlice[index] = value
        }
    }
    

Comparaison des approches :

Approche Sécurité Performance avec de grands slices Complexité
Copie du slice Élevée Moins (copie des données) Simple
Canaux Élevée Dépend (coût des opérations du canal) Moyenne
Mutexes Élevée Élevée (s’il n’y a pas de conflits importants) Moyenne

Ainsi, transmettre l’en-tête du slice à différentes goroutines sans synchronisation supplémentaire ou copie n’est pas sûr. Il faut utiliser l’une des méthodes ci-dessus pour assurer la sécurité des données.