Grow with AppMaster Grow with AppMaster.
Become our partner arrow ico

Concurrence en Go

Concurrence en Go

Introduction à la Concurrence en Go

La simultanéité est l'organisation de tâches indépendantes exécutées par un programme de manière simultanée ou pseudo-parallèle. La simultanéité est un aspect fondamental de la programmation moderne, permettant aux développeurs d'exploiter le plein potentiel des processeurs multicœurs, de gérer efficacement les ressources du système et de simplifier la conception d'applications complexes.

Go, également connu sous le nom de golang, est un langage de programmation compilé à typage statique, conçu dans un souci de simplicité et d'efficacité. Son modèle de simultanéité s'inspire des processus séquentiels communicants (CSP) de Tony Hoare, un formalisme qui encourage la création de processus indépendants interconnectés par des canaux explicites de transmission de messages. La simultanéité dans Go s'articule autour des concepts de goroutines, de canaux et de l'instruction "select".

Ces caractéristiques fondamentales permettent aux développeurs d'écrire des programmes hautement concurrents avec facilité et un minimum de code standard, tout en garantissant une communication et une synchronisation sûres et précises entre les tâches. Chez AppMaster, les développeurs peuvent exploiter la puissance du modèle de concurrence de Go pour créer des applications dorsales évolutives et performantes grâce à un concepteur visuel de plans et à la génération automatique de code source.

Goroutines : Les éléments constitutifs de la simultanéité

En Go, la concurrence s'articule autour du concept de goroutines, des structures légères de type thread gérées par le planificateur d'exécution de Go. Les goroutines sont incroyablement bon marché par rapport aux threads du système d'exploitation, et les développeurs peuvent facilement en créer des milliers, voire des millions, dans un seul programme sans surcharger les ressources du système. Pour créer une goroutine, il suffit de préfixer un appel de fonction avec le mot-clé "go". Lors de son invocation, la fonction s'exécutera simultanément avec le reste du programme :

func printMessage(message string) { fmt.Println(message) } func main() { go printMessage("Hello, concurrency !") fmt.Println("Ceci pourrait s'imprimer en premier.") }

Remarquez que l'ordre des messages imprimés n'est pas déterministe, et que le second message peut être imprimé avant le premier. Cela illustre le fait que les goroutines s'exécutent en même temps que le reste du programme et que leur ordre d'exécution n'est pas garanti. Le planificateur de Go est responsable de la gestion et de l'exécution des goroutines, en veillant à ce qu'elles s'exécutent simultanément tout en optimisant l'utilisation du processeur et en évitant les changements de contexte inutiles. Le planificateur de Go utilise un algorithme de vol de travail et planifie les goroutines de manière coopérative, en s'assurant qu'elles cèdent le contrôle lorsque c'est nécessaire, par exemple lors d'opérations de longue durée ou lors de l'attente d'événements réseau.

N'oubliez pas que les goroutines, bien qu'efficaces, ne doivent pas être utilisées sans précaution. Il est essentiel de suivre et de gérer le cycle de vie de vos goroutines pour garantir la stabilité de l'application et éviter les fuites de ressources. Les développeurs devraient envisager d'utiliser des modèles, tels que les pools de travailleurs, pour limiter le nombre de goroutines actives à un moment donné.

Canaux : Synchronisation et communication entre goroutines

Les canaux sont une partie fondamentale du modèle de concurrence de Go, permettant aux goroutines de communiquer et de synchroniser leur exécution en toute sécurité. Les canaux sont des valeurs de première classe en Go et peuvent être créés à l'aide de la fonction "make", avec une taille de tampon optionnelle pour contrôler la capacité :

// Canal sans tampon ch := make(chan int) // Canal avec tampon d'une capacité de 5 bufCh := make(chan int, 5)

L'utilisation d'un canal tampon avec une capacité spécifiée permet de stocker plusieurs valeurs dans le canal, qui sert de simple file d'attente. Cela peut contribuer à augmenter le débit dans certains scénarios, mais les développeurs doivent veiller à ne pas introduire de blocages ou d'autres problèmes de synchronisation. L'envoi de valeurs par l'intermédiaire de canaux s'effectue à l'aide de l'opérateur "<-" :

// Envoi de la valeur 42 via le canal ch <- 42 // Envoi de valeurs dans une boucle for i := 0 ; i < 10 ; i++ { ch <- i }

De même, la réception de valeurs à partir de canaux utilise le même opérateur '<-' mais avec le canal du côté droit :

// Réception d'une valeur du canal value := <-ch // Réception de valeurs dans une boucle for i := 0 ; i < 10 ; i++ { value := <-ch fmt.Println(value) }

Les canaux constituent une abstraction simple mais puissante pour la communication et la synchronisation des goroutines. En utilisant les canaux, les développeurs peuvent éviter les pièges courants des modèles à mémoire partagée et réduire la probabilité de courses aux données et d'autres problèmes de programmation concurrente. Prenons l'exemple suivant, dans lequel deux fonctions concurrentes additionnent les éléments de deux tranches et stockent les résultats dans une variable partagée :

Try AppMaster no-code today!
Platform can build any web, mobile or backend application 10x faster and 3x cheaper
Start Free
func sumSlice(slice []int, result *int) { sum := 0 for _, value := range slice { sum += value } *result = sum } func main() { slice1 := []int{1, 2, 3, 4, 5} slice2 := []int{6, 7, 8, 9, 10} sharedResult := 0 go sumSlice(slice1, &sharedResult) go sumSlice(slice2, &sharedResult) time.Sleep(1 * time.Second) fmt.Println("Result :", sharedResult) }

L'exemple ci-dessus est susceptible de donner lieu à des courses aux données, car les deux goroutines écrivent dans le même emplacement de mémoire partagée. L'utilisation de canaux permet de sécuriser la communication et d'éviter ce genre de problèmes :

func sumSlice(slice []int, ch chan int) { sum := 0 for _, value := range slice { sum += value } ch <- sum } func main() { slice1 := []int{1, 2, 3, 4, 5} slice2 := []int{6, 7, 8, 9, 10} ch := make(chan int) go sumSlice(slice1, ch) go sumSlice(slice2, ch) result1 := <-ch result2 := <-ch fmt.Println("Resultat :", result1 + result2) }

En utilisant les fonctionnalités concurrentielles intégrées de Go, les développeurs peuvent facilement créer des applications puissantes et évolutives. Grâce à l'utilisation de goroutines et de canaux, ils peuvent exploiter tout le potentiel du matériel moderne tout en conservant un code sûr et élégant. À l'adresse AppMaster, le langage Go permet aux développeurs de créer visuellement des applications dorsales, grâce à la génération automatique de code source, pour des performances et une évolutivité de premier ordre.

Modèles de simultanéité courants en Go

Les modèles de simultanéité sont des solutions réutilisables aux problèmes courants qui se posent lors de la conception et de la mise en œuvre de logiciels simultanés. Dans cette section, nous allons explorer quelques-uns des schémas de simultanéité les plus populaires en Go, y compris fan-in/fan-out, worker pools, pipelines, et plus encore.

Entrée/sortie en éventail (fan-in/fan-out)

Le modèle fan-in/fan-out est utilisé lorsque plusieurs tâches produisent des données (fan-out) et qu'une seule tâche consomme les données de ces tâches (fan-in). En Go, vous pouvez implémenter ce modèle en utilisant des goroutines et des canaux. La partie fan-out est créée en lançant plusieurs goroutines pour produire des données, et la partie fan-in est créée en consommant des données à l'aide d'un seul canal. ```go func FanIn(channels ...<-chan int) <-chan int { var wg sync.WaitGroup out := make(chan int) wg.Add(len(channels)) for _, c := range channels { go func(ch <-chan int) { for n := range ch { out <- n } wg.Done() }(c) } go func() { wg.Wait() close(out) }() return out } ```

Pools de travailleurs

Un worker pool est un ensemble de goroutines qui exécutent la même tâche de manière concurrente, en répartissant la charge de travail entre elles. Ce modèle est utilisé pour limiter la concurrence, gérer les ressources et contrôler le nombre de goroutines exécutant une tâche. En Go, vous pouvez créer un pool de travailleurs en utilisant une combinaison de goroutines, de canaux et le mot-clé "range". ```go func WorkerPool(workers int, jobs <-chan Job, results chan<- Result) { for i := 0 ; i < workers ; i++ { go func() { for job := range jobs { results <- job.Execute() } }() } } ```

Pipelines

Le modèle de pipeline est une chaîne de tâches qui traitent des données de manière séquentielle, chaque tâche transmettant sa sortie à la tâche suivante en tant qu'entrée. En Go, le modèle de pipeline peut être implémenté en utilisant une série de canaux pour passer des données entre les goroutines, avec une goroutine agissant comme une étape dans le pipeline. ```go func Pipeline(input <-chan Data) <-chan Result { stage1 := stage1(input) stage2 := stage2(stage1) return stage3(stage2) } ```

Limitation du débit

La limitation du débit est une technique utilisée pour contrôler la vitesse à laquelle une application consomme des ressources ou effectue une action particulière. Cette technique peut s'avérer utile pour gérer les ressources et éviter de surcharger les systèmes. En Go, vous pouvez implémenter la limitation de vitesse en utilisant time.Ticker et l'instruction 'select'. ```go func RateLimiter(requests <-chan Request, rate time.Duration) <-chan Response { limit := time.NewTicker(rate) responses := make(chan Response) go func() { defer close(responses) for req := range requests { <-limit.C responses <- req.Process() } }() return responses } ```

Try AppMaster no-code today!
Platform can build any web, mobile or backend application 10x faster and 3x cheaper
Start Free

Modèles d'annulation et de temporisation

Dans les programmes concurrents, il peut arriver que vous souhaitiez annuler une opération ou fixer un délai pour son achèvement. Go fournit le paquetage context, qui vous permet de gérer le cycle de vie d'une goroutine, ce qui permet de leur signaler d'annuler, de fixer une date limite, ou d'attacher des valeurs à partager à travers des chemins d'appel isolés. ```go func WithTimeout(ctx context.Context, duration time.Duration, task func() error) error { ctx, cancel := context.WithTimeout(ctx, duration) defer cancel() done := make(chan error, 1) go func() { done <- task() }() select { case <-ctx.Done() : return ctx.Err() case err := <-done : return err } } ```

Software Development

Gestion et récupération des erreurs dans les programmes simultanés

La gestion des erreurs et la récupération sont des composants essentiels d'un programme concurrent puissant, car ils permettent au programme de réagir à des situations inattendues et de poursuivre son exécution de manière contrôlée. Dans cette section, nous verrons comment gérer les erreurs dans les programmes concurrents Go et comment récupérer les paniques dans les goroutines.

Gestion des erreurs dans les programmes concurrents

  1. Envoyer les erreurs par l'intermédiaire de canaux: Vous pouvez utiliser des canaux pour passer des valeurs d'erreur entre les goroutines et laisser le récepteur les gérer en conséquence. ```go func worker(jobs <-chan int, results chan<- int, errs chan<- error) { for job := range jobs { res, err := process(job) if err != nil { errs <- err continue } results <- res } } ```
  2. Utilisez l'instruction "select": Lorsque vous combinez des canaux de données et d'erreurs, vous pouvez utiliser l'instruction 'select' pour écouter plusieurs canaux et effectuer des actions en fonction des valeurs reçues. ```go select { case res := <-results : fmt.Println("Result :", res) case err := <-errs : fmt.Println("Error :", err) } ```

Récupération des paniques dans les goroutines

Pour récupérer une panique dans une goroutine, vous pouvez utiliser le mot-clé 'defer' avec une fonction de récupération personnalisée. Cette fonction sera exécutée lorsque la goroutine rencontrera une panique et peut vous aider à gérer et à enregistrer l'erreur de manière élégante. ```go func workerSafe() { defer func() { if r := recover() ; r != nil { fmt.Println("Recovered from :", r) } }() // Votre code goroutine ici } ```

Optimiser les performances des programmes concurrents

L'amélioration des performances des programmes concurrents en Go implique principalement de trouver le bon équilibre entre l'utilisation des ressources et l'exploitation maximale des capacités matérielles. Voici quelques techniques que vous pouvez utiliser pour optimiser les performances de vos programmes concurrents en Go :

  • Ajustez le nombre de goroutines: Le nombre adéquat de goroutines dépend de votre cas d'utilisation spécifique et des limites de votre matériel. Expérimentez différentes valeurs pour trouver le nombre optimal de goroutines pour votre application.
  • Utiliser des canaux tamponnés: L'utilisation de canaux tamponnés peut augmenter le débit des tâches simultanées, en leur permettant de produire et de consommer davantage de données sans attendre la synchronisation.
  • Mettre en place une limitation de débit: L'utilisation d'une limitation de débit dans les processus gourmands en ressources permet de contrôler l'utilisation des ressources et d'éviter des problèmes tels que la contention, les blocages et les surcharges du système.
  • Utilisez la mise en cache: mettez en cache les résultats calculés auxquels vous accédez fréquemment, afin de réduire les calculs redondants et d'améliorer les performances globales de votre programme.
  • Établissez le profil de votreapplication: Profilez votre application Go à l'aide d'outils tels que pprof afin d'identifier et d'optimiser les goulets d'étranglement en matière de performances et les tâches consommatrices de ressources.
  • Exploitez AppMaster pour les applications dorsales: Lorsque vous utilisez la plateforme no-code AppMaster, vous pouvez créer des applications dorsales en tirant parti des capacités concurrentielles de Go, ce qui garantit des performances et une évolutivité optimales pour vos solutions logicielles.

En maîtrisant ces modèles de concurrence et ces techniques d'optimisation, vous pouvez créer des applications concurrentes efficaces et performantes en Go. Utilisez les fonctionnalités concurrentielles intégrées de Go avec la puissante plateforme AppMaster pour porter vos projets logiciels vers de nouveaux sommets.

Quelles techniques d'optimisation puis-je utiliser pour améliorer les performances des applications concurrentes en Go ?

Pour optimiser les applications concurrentes en Go, vous pouvez affiner le nombre de goroutines, utiliser des canaux tamponnés pour augmenter le débit, employer la limitation de taux pour contrôler l'utilisation des ressources, mettre en œuvre la mise en cache pour réduire les calculs redondants et profiler votre application pour identifier et optimiser les goulets d'étranglement en matière de performances. En outre, vous pouvez utiliser AppMaster pour construire des applications dorsales avec une programmation concurrente en Go, garantissant des performances et une évolutivité de premier ordre.

Qu'est-ce que la concurrence en Go ?

En Go, la simultanéité fait référence à la capacité d'un programme à exécuter plusieurs tâches simultanément ou, du moins, à les organiser de manière à ce qu'elles semblent s'exécuter en parallèle. Go comprend un support intégré pour la programmation simultanée grâce à l'utilisation de goroutines, de canaux et de l'instruction "select".

Quels sont les modèles de concurrence les plus courants en Go ?

Les modèles de concurrence courants en Go comprennent le modèle fan-in/fan-out, les pools de travailleurs, les pipelines, la limitation de vitesse et les annulations. Ces modèles peuvent être combinés et personnalisés pour construire des applications concurrentes puissantes et efficaces en Go.

Que sont les goroutines en Go ?

Les goroutines sont des structures légères de type thread gérées par le système d'exécution de Go. Elles constituent un moyen simple et efficace de créer et de gérer des milliers, voire des millions, de tâches simultanées. Les goroutines sont créées à l'aide du mot-clé "go" suivi d'un appel de fonction. Le planificateur du système d'exécution Go se charge de la gestion et de l'exécution simultanée des goroutines.

Comment gérer les erreurs et les paniques dans les programmes simultanés ?

En Go, vous pouvez gérer les erreurs dans les programmes concurrents en passant les valeurs d'erreur par des canaux, en utilisant l'instruction "select" pour gérer plusieurs sources d'erreur, et en utilisant le mot-clé "defer" avec une fonction de récupération pour intercepter et gérer les paniques qui peuvent se produire dans les goroutines.

Comment les canaux contribuent-ils à la concurrence ?

Les canaux en Go sont utilisés pour synchroniser et communiquer entre les goroutines. Ils permettent d'envoyer et de recevoir des données entre des tâches concurrentes, en garantissant une communication sûre et exempte de course aux données. Les canaux peuvent être non tamponnés ou tamponnés, en fonction de la capacité que vous spécifiez lors de la création.

Postes connexes

Système de gestion de l'apprentissage (LMS) et système de gestion de contenu (CMS) : principales différences
Système de gestion de l'apprentissage (LMS) et système de gestion de contenu (CMS) : principales différences
Découvrez les distinctions essentielles entre les systèmes de gestion de l’apprentissage et les systèmes de gestion de contenu pour améliorer les pratiques éducatives et rationaliser la diffusion de contenu.
Le retour sur investissement des dossiers médicaux électroniques (DME) : comment ces systèmes permettent d'économiser du temps et de l'argent
Le retour sur investissement des dossiers médicaux électroniques (DME) : comment ces systèmes permettent d'économiser du temps et de l'argent
Découvrez comment les systèmes de dossiers médicaux électroniques (DME) transforment les soins de santé avec un retour sur investissement significatif en améliorant l'efficacité, en réduisant les coûts et en améliorant les soins aux patients.
Systèmes de gestion des stocks basés sur le cloud ou sur site : lequel est le plus adapté à votre entreprise ?
Systèmes de gestion des stocks basés sur le cloud ou sur site : lequel est le plus adapté à votre entreprise ?
Explorez les avantages et les inconvénients des systèmes de gestion des stocks basés sur le cloud et sur site pour déterminer celui qui convient le mieux aux besoins uniques de votre entreprise.
Commencez gratuitement
Inspiré pour essayer cela vous-même?

La meilleure façon de comprendre la puissance d'AppMaster est de le constater par vous-même. Créez votre propre application en quelques minutes avec un abonnement gratuit

Donnez vie à vos idées