Maison  >  Article  >  développement back-end  >  Parlons de la programmation simultanée dans Go (1)

Parlons de la programmation simultanée dans Go (1)

咔咔
咔咔original
2021-07-07 16:13:502161parcourir

Parlons de la goroutine et de Channel

  • Avant-propos
  • 1 goroutine
    • Définition
    • Premier coup d'oeil au cas pour savoir comment utiliser goroutine
    • Qu'est-ce que c'est
  • 2.
    • Utilisation de base
    • will Channel est passé en paramètre
    • Créer plusieurs canaux
    • Utiliser le canal comme valeur de retour
    • canal tampon
    • le canal est fermé

    Articles connexes recommandés : "Parlez de la programmation simultanée dans Go ( 2)"

    Préface

Quand j'apprenais le langage Go auparavant, je l'ai sauté quand j'ai vu groutine et canal.

Je ne prenais pas ça du tout au sérieux à l’époque, pourquoi penses-tu que c’est si compliqué ? (Mon état d'esprit à l'époque)

Récemment, je regardais la programmation simultanée dans Go, et j'ai découvert que tout dépendait de cette partie du contenu, j'ai donc dû serrer les dents, mais vous constaterez que c'est ce n'est pas si difficile après l'avoir regardé.

Parfois, vous pouvez ranger des choses que vous ne voulez pas voir, puis les vérifier après avoir concentré votre attention. Vous obtiendrez des gains inattendus.

L'article d'aujourd'hui est une explication simple. Kaka s'est également inscrit à un cours de go. Je verrai si je peux mieux comprendre dans quel cours, puis je ferai des suppléments approfondis.

1. goroutine

Définition

  • Ajoutez simplement go avant la fonction
  • Il n'est pas nécessaire de distinguer s'il s'agit d'une fonction asynchrone dans la définition
  • Le planificateur fera l'affaire au point approprié. Il existe de nombreux points de commutation. Ceci n'est qu'une référence. Il n'y a aucune garantie de commutation ou qu'il ne sera pas commuté à d'autres endroits. Opérations IO, canaux, attente de verrous, appels de fonction, runtime.Gosched(), etc. . .
  • Utilisez race pour détecter les conflits d'accès aux données

Lisez d'abord le cas pour savoir comment utiliser goroutine

Regardons d'abord un cas

Parlons de la programmation simultanée dans Go (1)

Ce cas est un simple code d'exécution simultanée, qui n'est que le mot-clé go in go.

Jetons donc un coup d'œil à ce que ce code va générer

Parlons de la programmation simultanée dans Go (1)

D'après l'image ci-dessus, vous pouvez voir que cette ligne de code ne génère rien et se termine directement. Alors, que se passe-t-il exactement ?

La raison pour laquelle nous quittons directement est que les impressions main et fmt dans notre code sont exécutées simultanément. Si fmt imprime les données de toute urgence avant qu'elles n'arrivent, la boucle externe est déjà terminée, puis se termine directement.

Dans le langage go ! Supposons qu'après la sortie d'une fonction principale, elle tuera directement toutes les goroutines, le phénomène est donc que les données d'impression urgentes sont renvoyées avant l'arrivée de la goroutine.

Alors vous vous demandez, comment pouvez-vous voir les données imprimées ? En fait, c'est très simple, il suffit de ne pas quitter précipitamment après l'exécution de la fonction principale et de lui laisser un peu de temps pour attendre. Regardez le cas

Parlons de la programmation simultanée dans Go (1)

Le résultat souhaité cette fois est affiché.

Dans ce cas, le nombre de goroutines ouvertes est de 10, alors que se passera-t-il s'il passe à 1000 ?

Les résultats s'affichent toujours normalement, tout comme 1 000 personnes imprimant des choses en même temps.

Alors, qu'est-ce que le réglage 10 a à voir avec 1000 ?

Ceux qui connaissent le système d'exploitation doivent savoir qu'il n'y a aucun problème à ouvrir 10 threads, et qu'il n'y a pas de gros problème à ouvrir 100 threads, mais c'est presque suffisant.

Généralement, il suffit d'ouvrir des dizaines de threads dans le système, mais si 1 000 personnes doivent faire une chose en même temps, les threads ne peuvent pas être utilisés pour résoudre le problème et une méthode asynchrone est requise.

Mais en langue go ! Utilisez simplement le mot-clé go directement et il peut être exécuté simultanément.

Ensuite, parlons des raisons pour lesquelles Go peut imprimer 1 000 personnes en même temps.

Qu'est-ce que

Tout d'abord, jetons un coup d'œil à la différence entre les coroutines et les threads.

Coroutine peut être comprise comme Fil léger, Multitâche non préemptif, la coroutine cède activement le contrôle. 轻量级的线程非抢占式多任务处理,由协程主动交出控制权

线程大家应该都知道是可以被操作系统在任何时候进行切换,所以说线程就是抢占式多任务处理,线程是没有控制权,哪怕是一个语句执行到一半都会被操作系统切掉,然后转到其它线程去操作。

那么反之对于协程来说,什么时候交出控制权,什么时候不交出控制权是由协程内部主动决定的,正是因为这种非抢占式,所以被称之为轻量级。

并且多个协程是可以在一个或多个线程上运行的

Tout le monde doit savoir que les threads peuvent être commutés par le système d'exploitation à tout moment, les threads sont donc multitâches préemptifs. Même si une instruction est exécutée à mi-chemin, elle sera coupée par le système d'exploitation. allez sur d'autres threads pour fonctionner.

À l'inverse, pour la coroutine, quand céder les droits de contrôle et quand ne pas céder les droits de contrôle sont activement décidés par la coroutine C'est précisément à cause de ce style non préemptif qu'on l'appelle magnitude légère.
🎜🎜🎜etPlusieurs coroutines peuvent s'exécuter sur un ou plusieurs threads. 🎜🎜🎜🎜🎜🎜2. chaîne🎜🎜

Dans la première section, nous avons appris que vous pouvez ouvrir beaucoup de goroutines en go, puis le canal bidirectionnel entre les goroutines est le canal

Parlons de la programmation simultanée dans Go (1)

Utilisation de base

Parlons de la programmation simultanée dans Go (1)

Comme vous pouvez le voir dans le cas ci-dessus, vous pouvez directement utiliser la fonction make pour créer une chaîne.

Les septième et huitième lignes servent à envoyer des données au canal.

Alors cette affaire peut-elle être menée ? Venez l'essayer

Parlons de la programmation simultanée dans Go (1)

Vous pouvez voir qu'une erreur a été signalée à ce moment. L'erreur signifie qu'un blocage se produira lors de l'envoi de 1 au canal.

Retournez ensuite à la photo précédente.

Parlons de la programmation simultanée dans Go (1)

Comme nous l'avons dit plus haut, le canal est une interaction entre goroutine et goroutine.

Mais dans ce cas, il n'y a qu'une seule goroutine, il faut donc une autre goroutine pour la recevoir.

Maintenant, vous devriez savoir comment démarrer une goroutine.

Parlons de la programmation simultanée dans Go (1)

Dans l'image ci-dessus, nous avons récemment ouvert une autre goroutine, puis utilisé une boucle infinie pour recevoir la valeur envoyée par le canal et l'imprimer.

Mais vous constaterez que nous avons envoyé deux données au canal, mais le résultat de l'impression à ce moment ne contient qu'une seule donnée. Mais c’est mieux que ce avec quoi nous avons commencé, n’est-ce pas !

Alors pourquoi cela arrive-t-il ?

Vous pouvez comprendre le flux d'exécution du code. Tout d'abord, un 1 est envoyé au canal, puis la première valeur est obtenue dans une boucle et imprimée.

Envoyez à nouveau les données 2 au canal, mais quittez directement avant l'impression, ce qui entraîne le phénomène selon lequel seules les données 1 sont affichées mais pas les données 2.

Vous devriez déjà savoir comment résoudre ce problème grâce à la description de Kaka.

Il s'agit d'ajouter un temps de sortie retardé à la fonction ChannelDome.

Parlons de la programmation simultanée dans Go (1)

Passer le canal en paramètre

Comme vous pouvez le voir ci-dessus, go est suivi d'une fonction de fermeture, et le c utilisé dans cette fermeture est la couche externe utilisée c.

Alors est-il possible de passer ce c en utilisant des paramètres ? La réponse est oui.

Parlons de la programmation simultanée dans Go (1)

Bien sûr, vous pouvez également transmettre d'autres paramètres

Parlons de la programmation simultanée dans Go (1)

Vous pouvez voir sur l'image ci-dessus que non seulement le canal mais aussi le paramètre id sont transmis. En même temps, le code peut également être directement optimisé dans la partie ci-jointe, c'est-à-dire que la valeur est. pris directement de la chaîne.

Créez plusieurs chaînes

Parlons de la programmation simultanée dans Go (1)

Comme vous pouvez le voir sur l'image ci-dessus, chacun a sa propre chaîne, puis la distribue après distribution, chacun recevra sa propre valeur reçue et l'imprimera. ça sort.

De même, vous pouvez voir que nous avons ajouté une nouvelle boucle for à la ligne 26 pour envoyer des données au canal.

Parlons de la programmation simultanée dans Go (1)

D'après les résultats en cours, vous constaterez que l'ordre d'impression est déroutant, comme par exemple les deux valeurs​​reçois i et reçois I.

À ce stade, aurez-vous des doutes ? Lorsque nous envoyons des données à la chaîne, nous les envoyons dans l'ordre ! Ensuite, ils doivent être reçus dans l'ordre lors de la réception.

Comme nous sommes très sûrs que les données sont envoyées dans l'ordre, le problème ne peut survenir qu'avec Printf.

Parce que Printf a IO et est planifié par goroutine, alors Printf à ce moment est en panne, mais les valeurs reçues seront imprimées une par une.

Utiliser le canal comme valeur de retour

Les cas des sections précédentes ont tous été créés par canal puis transmis en tant que paramètres.

Ensuite, cette section renverra le canal comme valeur de retour.

Parlons de la programmation simultanée dans Go (1)

Code source

package mainimport (
	"fmt"
	"time")func createWorker(id int) chan int {
	c := make(chan int)
	go func() {
		for {
			fmt.Printf("Worker %d receive %c\n", id, 

De là, vous pouvez voir que nous avons changé la fonction worker en fonction createWorker, car dans cette fonction le canal est créé directement.

Ensuite, la valeur reçue par le canal est imprimée via une coroutine.

Retour de la chaîne.

Jetons un œil aux résultats en cours d'exécution

Parlons de la programmation simultanée dans Go (1)

Vous pouvez savoir grâce aux résultats en cours d'exécution que notre écriture de code est toujours correcte, mais vous pouvez voir comment utiliser le canal renvoyé à ce moment de manière très intuitive

Mais s'il y a beaucoup de codes, vous ne savez pas comment utiliser ce canal du tout Utilisé, tout ce code doit être simplement modifié.

Ensuite, ce qu'il faut faire, c'est dire aux gens de l'extérieur comment l'utiliser.

Parlons de la programmation simultanée dans Go (1)

Vous pouvez savoir à partir du code ci-dessus que les données sont envoyées au canal, donc le canal renvoyé par la méthode createWorker doit être marqué

Parlons de la programmation simultanée dans Go (1)

Le code actuel ressemble donc à ceci. Nous marquons directement la direction du canal de valeur de retour de la méthode createWorker. La fonction est d'envoyer des données.

Ensuite, lors de l'impression, c'est le reçu, qui semble très intuitif.

Après avoir modifié les deux étapes ci-dessus, vous constaterez createWorker调用是报错了,Cannot use 'createWorker(i)' (type chanLorsque vous voyez l'erreur, sachez que les deux types ne sont pas équivalents.

Parlons de la programmation simultanée dans Go (1)

Après modification, vous constaterez que la compilation est correcte et aucun message d'erreur n'est signalé.

Parlons de la programmation simultanée dans Go (1)也是ok的。

Parlons de la programmation simultanée dans Go (1)

本小节源码

package mainimport (
	"fmt"
	"time")func createWorker(id int) chan

buffer channel

学习了这么久了,那么咔咔问你一个问题,这段代码执行会发生什么?

Parlons de la programmation simultanée dans Go (1)

Oui, une erreur se produira, car comme mentionné au début de l'article, pour envoyer des données à un canal, vous devez ouvrir une autre coroutine pour recevoir les données.

Bien que les coroutines soient considérées comme légères, après l'envoi de données, vous devez changer de coroutines pour recevoir des données, ce qui nécessite beaucoup de ressources.

Alors c’est ce que je vais vous expliquer dans cette section.

buffer channel

Créez un canal pouvant avoir 3 tampons, puis envoyez 3 données au canal.

Vous pouvez également savoir grâce aux résultats de la course à pied en même temps que cela ne se produit pasdeadlock.

Une question pour vous, que se passera-t-il si vous envoyez une donnée 4 au tampon ?

Parlons de la programmation simultanée dans Go (1)

Vous êtes intelligent, vous devez avoir pensé au résultat, oui, l'avez signalédeadlock

Ensuite, nous utiliserons le travailleur précédent pour recevoir les données du canal.

Parlons de la programmation simultanée dans Go (1)

Mais vous constaterez que le résultat en cours d'exécution n'imprime toujours pas le 1,2,3,4 envoyé.

Cette question a été posée plusieurs fois maintenant. Vous pouvez essayer de vous demander comment résoudre cette situation.

Parlons de la programmation simultanée dans Go (1)

Ajoutez simplement un temps de retard. Au fait, laissez-moi vous expliquer que le cas précédent imprimait les lettres et tout le formatage %c, maintenant il imprime les chiffres, donc changez Pour %d, un petit changement. .

L'établissement de canaux de cette manière a un certain effet sur l'amélioration des performances.

Avez-vous découvert un problème jusqu'à présent, c'est-à-dire que vous ne savez pas quand la chaîne a été envoyée ?

Examinons ensuite ce problème.

chaîne fermée

Empruntez le code du cas précédent pour continuer l'explication.

Parlons de la programmation simultanée dans Go (1)
Ce qui est incohérent avec le code précédent, c'est que nous avons ajouté close à la fin. Il est à noter que close est fermé sur l'expéditeur.

Vous verrez que les résultats en cours ne sont pas satisfaisants, vous constaterez que même si 1,2,3,4 sont reçus.

Mais de nombreux 0 ont été reçus ci-dessous, mais la capture d'écran n'a capturé qu'une seule donnée.

Bien que l'expéditeur ferme le canal, le travailleur recevra toujours les données lorsque le canal sera fermé. Cela ne signifie pas que les données ne seront pas reçues après la fermeture du canal.

Mais lorsque l'expéditeur définit la fermeture de canal, les données reçues sont toutes 0, c'est-à-dire que la valeur du paramètre c chan int transmis par la méthode de travail est 0.

Maintenant, notre chaîne est de type int, et nous avons reçu 0. Ensuite, s’il s’agit d’un type chaîne, ce qui est reçu est une chaîne vide.

Combien de temps cela prendra-t-il ? C'est le temps d'une milliseconde que nous avons fixé.

Si on vous demandait de changer ce programme, avez-vous des idées ? Si vous n’en avez aucune idée, balancez-vous simplement au rythme de ce clic.

Parlons de la programmation simultanée dans Go (1)

Dans la fonction worker, deux valeurs sont utilisées pour recevoir, n est le canal c transmis. ok est de déterminer si la valeur existe.

Vous pouvez voir les résultats en cours et vous ne recevrez plus 0 données.

En plus de cette façon d'écrire, il existe une manière plus simple.

Parlons de la programmation simultanée dans Go (1)

La persévérance dans l'apprentissage, la persévérance dans l'écriture et la persévérance dans le partage sont les convictions auxquelles Kaka a toujours adhéré depuis ses débuts. J'espère que les articles de Kaka sur le grand Internet pourront vous apporter un peu d'aide. Je m'appelle Kaka, à la prochaine fois.

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:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn