ProgrammationDéveloppeur Backend Go Middle

Que se passe-t-il lors de la transmission de valeurs par canal en Go : comment fonctionne la copie, quels types sont transmis par valeur, comment peut-on accidentellement obtenir une condition de course lors de la transmission de structures complexes ou de pointeurs ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

En Go, il est possible d'envoyer des valeurs de n'importe quel type par des canaux : int, struct, pointeurs, interfaces, etc.

  • Transmission « par valeur » : les types standards et les structures (sans pointeurs) sont copiés, le destinataire reçoit sa propre copie, et les modifications n'affectent pas l'original.
  • Vérification des conditions de course : si un pointeur est transmis par le canal, les deux parties (expéditeur et destinataire) travaillent avec la même zone mémoire — une condition de course est possible !
  • Structures complexes avec des pointeurs imbriqués : même si la structure principale est transmise par valeur, les pointeurs imbriqués sont copiés comme des références, et une condition de course est possible au niveau des objets imbriqués.

Code et exemple :

type Data struct { N int } c := make(chan Data) d := Data{N: 1} c <- d // la structure est entièrement copiée p := &Data{N: 3} c2 := make(chan *Data) c2 <- p // un pointeur vers le même objet est envoyé par le canal

Question piégée

Si une structure contenant un champ pointeur est transmise par le canal — y aura-t-il une condition de course lors de la modification de ce champ aux deux extrémités du canal ?

Réponse :

  • Une condition de course est possible ! La structure est copiée, mais le pointeur imbriqué fait référence à la même zone mémoire. Si les deux parties modifient les données par référence, une condition de course se produit.

Exemple :

type Box struct { Ptr *int } x := 10 chanBox := make(chan Box) chanBox <- Box{Ptr: &x} // l'expéditeur et le destinataire ont tous deux accès à x !

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet


Histoire

Dans une file d'attente distribuée, il y avait des arrêts "aléatoires" fréquents et des valeurs mystérieuses dans la structure de la tâche. Il s'est avéré que des pointeurs vers des structures communes étaient transférés par le canal, qui étaient modifiés en parallèle dans plusieurs goroutines. Nous avons décidé de passer à la transmission de copies de données.


Histoire

Le traitement asynchrone des messages fonctionnait avec des structures contenant des tranches-pointeurs vers un tableau commun. Lors de la transmission parallèle par le canal, des parties de la même mémoire étaient modifiées depuis différents endroits, entraînant des bogues secrets et une corruption des données.


Histoire

Dans le service de notifications push, des références à des objets étaient transmises par le canal, qui étaient ensuite traitées par des goroutines. Lors de la terminaison simultanée et de la fermeture du canal, certaines structures étaient encore modifiées, provoquant une panique ou une condition de course. Le passage à la copie de la structure avant l'envoi a aidé.