Partage de technologie

Langage Go --- canal de programmation simultané (double canal, canal unique) et exemples d'application (producteur consommateur, modèle d'imprimante)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Canal

Les goroutines s'exécutent dans le même espace d'adressage, l'accès à la mémoire partagée doit donc être synchronisé.Les Goroutines partagent la mémoire via la communication, plutôt que de partager la mémoire.

Le canal de type référence est une implémentation spécifique du mode CSP et est utilisé pour la communication entre plusieurs goroutines. Il implémente la synchronisation en interne pour garantir la sécurité de la concurrence.

type de canal

Comme map, channel est également une référence à la structure de données sous-jacente créée par make.
Lorsque nous copions un canal ou l'utilisons pour le passage de paramètres de fonction, nous copions simplement une référence de canal, de sorte que l'appelant et l'appelé référenceront le même objet de canal. Comme les autres types de référence, la valeur zéro du canal est nulle.
Lorsque vous définissez un canal, vous devez également définir le type de valeurs envoyées au canal. Les canaux peuvent être créés à l'aide de la fonction make() intégrée :

make (chan Type)
make (chan Type,capacity)
  • 1
  • 2
  • Lorsque capacité = 0, le canal n'est pas tamponné et bloque la lecture et l'écriture. Lorsque capacité > 0, le canal dispose d'un cache et n'est pas bloquant. L'écriture ne sera pas bloquée jusqu'à ce que les éléments de capacité soient remplis.
  • Chamnel reçoit et envoie des données via l'opérateur <- La syntaxe d'envoi et de réception des données est :
channel<-value   //发送value 到channel
<-channel     //接收并将其丢弃
x:=<-channel   //从 channel 中接收数据,并賦偵给x
x,ok:=<-channel   //功能同上,同时检查通道是否已关闭或者是否为空
  • 1
  • 2
  • 3
  • 4

Par défaut, le canal se bloque lors de la réception et de l'envoi de données, à moins que l'autre extrémité ne soit prête, ce qui simplifie la synchronisation des goroutines sans avoir besoin de verrous explicites.

accomplir

Insérer la description de l'image ici

  • Les tuyaux sont placés un devant l’impression et un au dos de l’impression.
  • Si Person2 est exécuté en premier et qu'il n'y a aucune donnée dans le pipeline, il se bloquera.
  • Person1 s'exécute et après avoir imprimé les données, entrez les données dans le canal Person2 les détectera et commencera l'impression.

Mettre en œuvre la synchronisation et l'interaction des données via des canaux

Insérer la description de l'image ici
Insérer la description de l'image ici

canal sans tampon

Un canal sans tampon est un canal qui n'a aucune capacité à enregistrer une valeur avant de la recevoir.
Ce type de canal nécessite que la goroutine d'envoi et la goroutine de réception soient prêtes en même temps à terminer les opérations d'envoi et de réception. Si deux goroutines ne sont pas prêtes en même temps, le canal provoquera le blocage et l'attente de la goroutine qui effectue l'opération d'envoi ou de réception en premier.
Cette interaction d'envoi et de réception sur le canal est intrinsèquement synchrone. Aucune opération ne peut exister indépendamment des autres.
La figure suivante montre comment deux goroutines peuvent partager une valeur en utilisant des canaux sans tampon :
Insérer la description de l'image ici

  • C'est-à-dire que le canal lui-même ne peut pas stocker des éléments. Si vous y mettez quelque chose, vous pouvez le retirer immédiatement.
  • À l'étape 1, les deux goroutines arrivent sur le canal, mais aucune ne commence à envoyer ou à recevoir.
  • À l'étape 2, la goroutine de gauche met la main dans le canal, ce qui simule l'envoi de données au canal. A ce moment, la goroutine sera verrouillée dans le canal jusqu'à ce que l'échange soit terminé.
  • À l'étape 3, la goroutine de droite met la main dans le canal, ce qui simule la réception de données du canal. Cette goroutine sera également verrouillée dans le canal jusqu'à ce que l'échange soit terminé.
  • Aux étapes 4 et 5, un échange a lieu, et enfin, à l'étape 6, les deux goroutines retirent leurs mains du canal, ce qui simule la libération de la goroutine verrouillée. Les deux goroutines peuvent désormais faire autre chose.

Créer un canal sans tampon

make (chan Type)//等价于make (chan Type,0)
  • 1

Si aucune taille de tampon n'est spécifiée, le canal est synchrone et se bloque donc jusqu'à ce que l'expéditeur soit prêt à envoyer et que le récepteur soit prêt à recevoir.

Insérer la description de l'image ici

  • ch&lt;-i écrit les données sur le canal et la coroutine principale ne s'exécutera pas tant qu'elle ne le détectera pas. À ce moment-là, la sous-coroutine bloquera également et attendra une fois que le canal aura lu les données, la sous-coroutine continuera. .
  • Cependant, println imprime les données après la lecture du tube, la vitesse d'impression est donc déterminée par le système.

canal tamponné

Un canal tamponné est un canal capable de stocker une ou plusieurs valeurs avant d'être reçu.
Ce type de canal ne nécessite pas que la goroutine termine l'envoi et la réception en même temps. Les canaux auront également des conditions différentes qui bloquent les actions d'envoi et de réception. L'action de réception ne bloquera que s'il n'y a aucune valeur dans le canal à recevoir. L'action d'envoi ne bloquera que si le canal n'a pas de tampon disponible pour accueillir la valeur envoyée.
Cela conduit à une grande différence entre les canaux tamponnés et non tamponnés : les canaux non tamponnés garantissent que les goroutines d'envoi et de réception échangeront des données en même temps : les canaux tamponnés n'ont pas une telle garantie.
Insérer la description de l'image ici

  • À l'étape 1, la goroutine de droite reçoit une valeur du canal.
  • À l'étape 2, la goroutine de droite termine l'action de réception de la valeur de manière indépendante, tandis que la goroutine de gauche envoie une nouvelle valeur au canal.
  • À l'étape 3, la goroutine de gauche envoie toujours une nouvelle valeur au canal, tandis que la goroutine de droite reçoit une autre valeur du canal. Les deux opérations de cette étape ne sont ni synchronisées ni se bloquent.
  • Enfin, à l'étape 4, tous les envois et réceptions sont terminés, et il reste encore quelques valeurs dans le canal et un peu d'espace pour stocker plus de valeurs.

créer

make (chan Type,capacity)
  • 1

Si une capacité tampon est donnée, le canal est asynchrone. Tant que le tampon dispose d'un espace inutilisé pour l'envoi de données ou contient des données pouvant être reçues, la communication se poursuit sans blocage.

accomplir

Insérer la description de l'image ici

  • Si suffisamment de trois sont stockées, elle se bloquera et attendra la lecture. Lorsque la coroutine principale aura lu une donnée et qu'il y aura de l'espace libre, la sous-coroutine continuera à s'exécuter et l'ordre d'impression ultérieur ne sera pas certain.
    Insérer la description de l'image ici

fermer le canal

Le canal peut utiliser ok pour détecter si le canal est toujours ouvert. Si le canal est fermé, les données ne seront pas lues.

Insérer la description de l'image ici

  • num ,ok:=<-chPeut détecter si un canal est fermé.

Avis

  • Les canaux n'ont pas besoin d'être fermés fréquemment comme les fichiers. Fermez le canal uniquement lorsque vous n'avez vraiment aucune donnée à envoyer, ou si vous souhaitez terminer explicitement la boucle de plage ou similaire ;
  • Après la fermeture du canal, plus aucune donnée ne peut être envoyée au canal (une erreur de panique se déclenche, provoquant le renvoi immédiat d'une valeur nulle à la réception) :
  • Après avoir fermé la chaîne, vous pouvez continuer à recevoir des données du canal :
  • Pour les chaînes nulles, l'envoi et la réception seront bloqués.
    Insérer la description de l'image ici
  • Vous pouvez utiliser la plage pour parcourir le canal et sortir automatiquement de la boucle
    Insérer la description de l'image ici

Canal unidirectionnel

Par défaut, le canal est à double question, c'est-à-dire que vous pouvez lui envoyer des données et en recevoir.
Cependant, nous voyons souvent un canal passé en paramètre et la valeur est censée être utilisée dans un sens, soit uniquement pour envoyer des données, soit uniquement pour recevoir des données. À ce stade, nous pouvons spécifier la direction du canal. La déclaration d'une variable chamel unidirectionnelle est très simple, comme suit :

var ch1 chan int //ch1双向
var ch2 chan<-float64 //ch2单向,只能用于写float64数据
var ch3 <-chan int  //ch3单向,只能用于读int数据
  • 1
  • 2
  • 3

chan&lt;- signifie que les données entrent dans le canal et que les données sont écrites dans le canal, qui est transmis à l'appelant.
&lt;-chan indique que les données sortent du tube. Pour l'appelant, les données du tube sont obtenues, qui sont bien sûr l'entrée.
Un canal peut être implicitement converti en une file d'attente unidirectionnelle, recevant uniquement ou envoyant uniquement, mais un canal unidirectionnel ne peut pas être converti en un canal normal ;

Insérer la description de l'image ici

Utiliser un canal unique pour mettre en œuvre le modèle producteur-consommateur

Insérer la description de l'image ici