À quoi sert exactement le langage Go?

L'équipe de développement du langage Go a mis beaucoup de temps à résoudre les problèmes rencontrés par les développeurs de logiciels aujourd'hui. Lors du choix d'un langage pour un projet, les développeurs doivent choisir entre un développement rapide et des performances. Des langages tels que C et C ++ fournissent une vitesse d'exécution rapide, tandis que des langages tels que Ruby et Python sont bons pour un développement rapide. Le langage Go crée un pont entre les deux, non seulement en fournissant un langage hautes performances, mais en accélérant également le développement.

Dans le processus d'exploration du langage Go, les lecteurs verront des fonctionnalités bien conçues et une syntaxe concise. En tant que langage, Go définit non seulement ce qui peut être fait, mais aussi ce qui ne peut pas être fait. La syntaxe du langage Go est concise à seulement quelques mots-clés, ce qui est facile à retenir. Le compilateur du langage Go est très rapide et parfois les gens ne se sentent même pas en train de compiler. Par conséquent, les développeurs Go peuvent réduire considérablement le temps d'attente pour le projet à construire. Le langage Go étant doté d'un mécanisme d'accès concurrentiel intégré, vous pouvez étendre le logiciel et utiliser plus de ressources sans être obligé d'utiliser une bibliothèque de threads spécifique. Le système de type du langage Go est simple et efficace, et ne nécessite pas de mentalité supplémentaire pour le développement orienté objet, permettant aux développeurs de se concentrer sur la réutilisation du code. Go language est également livré avec un garbage collector, qui ne nécessite pas que les utilisateurs gèrent eux-mêmes la mémoire. Jetons un coup d'œil à ces fonctionnalités clés.

1.1.1 Vitesse de développement

Le temps nécessaire pour compiler un grand projet C ou C ++ est encore plus long que le temps nécessaire pour prendre une tasse de café. La figure 1-1 est un dessin animé dans XKCD qui décrit les excuses classiques pour s'échapper au bureau.

 

Figure 1-1 Vous travaillez dur? (À partir de XKCD)

Le langage Go utilise un compilateur plus intelligent et simplifie l'algorithme de résolution des dépendances, offrant finalement une vitesse de compilation plus rapide. Lors de la compilation d'un programme Go, le compilateur ne prête attention qu'aux bibliothèques qui sont directement référencées, au lieu de parcourir toutes les bibliothèques dépendantes de la chaîne de dépendances comme Java, C et C ++. Par conséquent, de nombreux programmes Go peuvent être compilés en 1 seconde. Sur le matériel moderne, la compilation de l'ensemble de l'arborescence des sources du langage Go ne prend que 20 secondes.

Comme il n'y a pas de processus intermédiaire entre la compilation du code et l'exécution du code, vous pouvez voir rapidement la sortie lorsque vous écrivez une application dans un langage dynamique. Le prix est que les langages dynamiques ne fournissent pas les fonctionnalités de sécurité de type fournies par les langages statiques, et un grand nombre de suites de tests doivent être utilisées pour éviter des bogues tels que des erreurs de type lors de l'exécution.

Imaginez développer une grande application dans un langage dynamique comme JavaScript, et une fonction s'attend à recevoir un champ appelé ID. Ce paramètre doit-il être un entier, une chaîne ou un UUID? Pour connaître la réponse, vous ne pouvez regarder que le code source. Vous pouvez essayer d'exécuter cette fonction avec un nombre ou une chaîne et voir ce qui se passe. Dans le langage Go, vous n'avez pas à vous en soucier du tout, car le compilateur peut aider les utilisateurs à détecter ce type d'erreur.

1.1.2 Concurrence

En tant que programmeur, il est difficile de développer des applications capables d'utiliser pleinement les ressources matérielles. Les ordinateurs modernes ont plusieurs cœurs, mais la plupart des langages de programmation ne disposent pas d'outils efficaces pour permettre aux programmes d'utiliser facilement ces ressources. Ces langages doivent écrire beaucoup de code de synchronisation de threads pour utiliser plusieurs cœurs, ce qui peut facilement conduire à des erreurs.

Le support de Go language pour la concurrence est l'une des fonctionnalités les plus importantes de ce langage. Un goroutine est très similaire à un thread, mais il prend beaucoup moins de mémoire qu'un thread et nécessite moins de code pour l'utiliser. Un canal est une structure de données intégrée qui permet aux utilisateurs d'envoyer de manière synchrone des types de messages entre différents goroutines. Cela rend le modèle de programmation plus enclin à envoyer des messages entre les goroutines, plutôt que de permettre à plusieurs goroutines de se disputer le droit d'utiliser les mêmes données. Regardons les détails de ces fonctionnalités.

1.goroutine

Un goroutine est une fonction qui peut être exécutée en parallèle avec d'autres goroutines, et également en parallèle avec le programme principal (entrée de programme). Dans d'autres langages de programmation, vous devez utiliser des threads pour accomplir la même chose, tandis que dans Go, le même thread est utilisé pour exécuter plusieurs goroutines. Par exemple, un utilisateur écrit un serveur Web et souhaite traiter différentes requêtes Web en même temps. Si vous utilisez C ou Java, vous devez écrire beaucoup de code supplémentaire pour utiliser les threads. Dans le langage Go, la bibliothèque net / http utilise directement la goroutine intégrée. Chaque requête reçue est automatiquement traitée dans sa propre goroutine. Le goroutine utilise moins de mémoire que le thread, et le langage Go planifie automatiquement l'exécution de la goroutine sur l'ensemble configuré de processeurs logiques lors de l'exécution. Chaque processeur logique est lié à un thread du système d'exploitation (voir la figure 1-2). Cela rend l'exécution des applications de l'utilisateur plus efficace et la charge de travail de développement est considérablement réduite.

 

Figure 1-2 Exécuter plusieurs goroutines sur un seul thread système

Si vous voulez exécuter un morceau de code tout en faisant d'autres choses en parallèle, goroutine est un bon choix. Voici un exemple simple:

func log(msg string) {
    ...这里是一些记录日志的代码
}

// 代码里有些地方检测到了错误
go log("发生了可怕的事情")

Le mot-clé go est le seul code à écrire, et la fonction de journalisation est planifiée pour s'exécuter en tant que goroutine indépendante pour s'exécuter en parallèle avec d'autres goroutines. Cela signifie que le reste de l'application sera exécuté en parallèle avec la journalisation, ce qui permet généralement à l'utilisateur final de se sentir mieux. Comme mentionné précédemment, les goroutines prennent moins de ressources, de sorte que des milliers de goroutines peuvent souvent être démarrées. Nous explorerons plus en profondeur les goroutines et la concurrence dans le chapitre 6.

2. rayon

Un canal est une structure de données qui permet une communication de données sécurisée entre les goroutines. Les canaux peuvent aider les utilisateurs à éviter les problèmes courants d'accès à la mémoire partagée dans d'autres langues.

La partie la plus difficile de la concurrence est de s'assurer que d'autres processus, threads ou goroutines exécutés simultanément ne modifient pas accidentellement les données utilisateur. Lorsque différents threads modifient les mêmes données sans protection de synchronisation, des catastrophes se produisent toujours. Dans d'autres langues, si vous utilisez des variables globales ou de la mémoire partagée, vous devez utiliser des règles de verrouillage complexes pour empêcher les modifications asynchrones de la même variable.

Afin de résoudre ce problème, le canal fournit un nouveau mode pour assurer la sécurité des données lors de modifications simultanées. Canal a

 

Figure 1-3 Utilisation des canaux pour envoyer des données en toute sécurité entre les goroutines

Dans la figure 1-3, il y a 3 goroutines et 2 canaux sans cache. Le premier goroutine transmet des données via le canal au second goroutine qui attend déjà. La transmission des données entre deux goroutines est synchrone Une fois la transmission terminée, les deux goroutines sauront que les données ont été transmises. Lorsque le deuxième goroutine utilise ces données pour terminer sa tâche, il transmet ces données au troisième goroutine qui attend. Cette fois, la transmission est toujours synchronisée et les deux goroutines confirmeront que la transmission des données est terminée. Cette méthode de transfert de données en toute sécurité entre les goroutines ne nécessite aucun mécanisme de verrouillage ou de synchronisation.

Il convient de souligner que le canal ne fournit pas de mécanisme de protection d'accès aux données inter-goroutine. Si une copie des données est transmise via le canal, alors chaque goroutine en détient une copie, et il est prudent pour chacun de modifier sa propre copie. Lors de la transmission d'un pointeur vers des données, si la lecture et l'écriture sont effectuées par des goroutines différentes, chaque goroutine a encore besoin d'actions de synchronisation supplémentaires.

1.1.3 Système de type de langue Go

Le langage Go fournit un système de type flexible, sans héritage, qui peut réutiliser le code au maximum sans réduire les performances d'exploitation. Ce système de type prend toujours en charge le développement orienté objet, mais évite les problèmes orientés objet traditionnels. Si vous avez déjà passé des semaines à réfléchir à la manière d'abstraire des classes et des interfaces sur des programmes Java et C ++ complexes, vous vous rendrez compte à quel point le système de types du langage Go est simple. Les développeurs Go utilisent le modèle de conception de composition et incorporent simplement un type dans un autre type pour réutiliser toutes les fonctions. La composition peut également être utilisée dans d'autres langues, mais elle doit être combinée avec l'héritage, ce qui rend l'utilisation dans son ensemble très compliquée et difficile à utiliser. Dans le langage Go, un type par un autre type de combinaison plus mineur est fait pour éviter le modèle traditionnel basé sur l'héritage.

En outre, le langage Go dispose également d'un mécanisme d'implémentation d'interface unique qui permet aux utilisateurs de modéliser le comportement au lieu de modéliser. Dans le langage Go, il n'est pas nécessaire de déclarer qu'un certain type implémente une interface. Le compilateur déterminera si une instance d'un type est conforme à l'interface utilisée. De nombreuses interfaces de la bibliothèque standard Go sont très simples et n'ouvrent que quelques fonctions. Concrètement, en particulier pour ceux qui utilisent des langages orientés objet comme Java, il faut un certain temps pour s'habituer à cette fonctionnalité.

1. Type simple

Le langage Go a non seulement des types intégrés tels que int et string, mais prend également en charge les types définis par l'utilisateur. Dans le langage Go, les types définis par l'utilisateur contiennent généralement un ensemble de champs typés pour stocker les données. Les types de langage Go définis par l'utilisateur ressemblent beaucoup à la structure du langage C, et ils sont également très similaires à utiliser. Cependant, les types de langage Go peuvent déclarer des méthodes pour manipuler des données de ce type. Les langages traditionnels utilisent l'héritage pour étendre la structure: le client hérite de l'utilisateur, l'utilisateur hérite de l'entité. Contrairement au langage Go, les développeurs Go créent des types plus petits - client et administrateur, puis combinent ces petits types en types plus grands . La figure 1-4 montre la différence entre l'héritage et la composition.

 

Figure 1-4 Comparaison de l'héritage et de la composition

2. L'interface Go modélise un ensemble de comportements

Les interfaces sont utilisées pour décrire le comportement des types. Si une instance d'un type implémente une interface, cela signifie que l'instance peut effectuer un ensemble spécifique de comportements. Vous n'avez même pas besoin de déclarer que cette instance implémente une interface, il vous suffit d'implémenter cet ensemble de comportements. D'autres langues appellent cette fonctionnalité un type de canard - si cela ressemble à un canard, alors il peut s'agir d'un canard. L'interface de langue Go fait de même. Dans le langage Go, si un type implémente toutes les méthodes d'une interface, alors l'instance de ce type peut être stockée dans l'instance du type d'interface sans déclaration supplémentaire.

Dans un langage orienté objet strict comme Java, toute la conception tourne autour des interfaces. Avant de coder, les utilisateurs doivent souvent penser à une énorme chaîne d'héritage. Voici un exemple d'interface Java:

interface User {
    public void login();
    public void logout();
}

Pour implémenter cette interface en Java, la classe de l'utilisateur doit respecter toutes les contraintes de l'interface utilisateur et la classe doit être explicitement déclarée pour implémenter cette interface. L'interface du langage Go ne décrit généralement qu'une seule action. Dans le langage Go, l'une des interfaces les plus couramment utilisées est io.Reader. Cette interface fournit une méthode simple pour déclarer qu'un type a des données à lire. D'autres fonctions de la bibliothèque standard peuvent comprendre cette interface. La définition de cette interface est la suivante:

type Reader interface {
    Read(p []byte) (n int, err error)
}

Pour implémenter l'interface io.Reader, il vous suffit d'implémenter une méthode Read, qui accepte une tranche d'octet et renvoie un entier et des erreurs possibles.

Ceci est essentiellement différent du système d'interface des langages de programmation orientés objet traditionnels. L'interface du langage Go est plus petite et ne tend à définir qu'une seule action. En utilisation réelle, cela est plus propice à l'utilisation d'une combinaison pour réutiliser le code. Les utilisateurs peuvent implémenter l'interface io.Reader pour presque tous les types contenant des données, puis transmettre une instance de ce type à toute fonction Go qui sait lire io.Reader.

L'ensemble de la bibliothèque réseau du langage Go utilise l'interface io.Reader, qui permet de séparer la fonction du programme de l'implémentation de différents réseaux. Une telle interface est amusante, élégante et gratuite. Les fichiers, tampons, sockets et autres sources de données implémentent tous l'interface io.Reader. En utilisant la même interface, vous pouvez manipuler les données efficacement, quelle que soit leur origine.

1.1.4 Gestion de la mémoire

Une mauvaise gestion de la mémoire peut provoquer des pannes de programme ou des fuites de mémoire, voire même planter l'ensemble du système d'exploitation. Le langage Go dispose d'un mécanisme de récupération de place moderne qui peut vous aider à résoudre ce problème. Dans d'autres langages système (tels que C ou C ++), cette mémoire doit être allouée avant de l'utiliser et elle doit être libérée après son utilisation. Même si vous ne faites qu'une seule chose de mal, cela peut provoquer le blocage du programme ou une fuite de mémoire. Malheureusement, suivre si la mémoire est toujours utilisée est très difficile en soi, et il est encore plus difficile de prendre en charge le multi-threading et une concurrence élevée. Bien que le garbage collection du langage Go ait une surcharge supplémentaire, il peut réduire considérablement la difficulté de développement lors de la programmation. Le langage Go délègue la gestion ennuyeuse de la mémoire aux compilateurs professionnels, permettant aux programmeurs de se concentrer sur des choses plus intéressantes.

Cet article est extrait de "Go Language Practice"

 

Le langage Go combine les capacités du langage système sous-jacent et les fonctionnalités avancées des langues modernes, dans le but de réduire les obstacles à la création de logiciels simples, fiables et efficaces. Ce livre offre aux lecteurs une perspective ciblée, complète et linguistique. Ce livre se concentre également sur la spécification et l'implémentation du langage, et le contenu impliqué comprend la grammaire, le système de type, la concurrence, les pipelines, les tests et d'autres sujets.

Ce livre est écrit pour les développeurs intermédiaires qui ont une base dans d'autres langages de programmation et une certaine expérience du développement qui veulent apprendre Go. Ce livre est le meilleur choix pour les personnes qui commencent tout juste à apprendre la langue Go et qui souhaitent en savoir plus sur l'implémentation interne de la langue Go.

Je suppose que tu aimes

Origine blog.csdn.net/epubit17/article/details/108233560
conseillé
Classement