Le langage Go fête ses 4 ans

Posté par  . Édité par Florent Zara, claudex, Benoît Sibaud et Bruno Michel. Modéré par patrick_g. Licence CC By‑SA.
57
13
nov.
2013
Golang

Le langage Go, parfois nommé Golang et créé principalement par Robert Griesemer, Rob Pike et Ken Thompson (des grands noms, que dis-je, des légendes du monde UNIX), chez Google, vient de fêter ses 4 ans. Le langage semble commencer à trouver des applications dans des projets de grande envergure, au delà de projets internes à Google. Pour un langage relativement jeune, c'est encourageant.

logo Go

NdM : 2 composants de LinuxFr.org sont codés en Go, img et epub.

Sommaire

Généralités

Conçu pour la programmation système (au sens « applications sans interaction avec l'utilisateur humain », pas au sens « programmation kernel »), Go vise à pallier un certain nombre de défauts de C++ (notamment au regard de la lenteur de la compilation, de la complexité du langage et des défaillances au niveau de l'outillage). Ce qui se voulait être un successeur de C semble surtout rencontrer du succès auprès des aficionados des langages à typage dynamique, notamment Python et Ruby, à la grande surprise de ses concepteurs.

Le langage a subi de multiples influences. C, bien entendu, puisque le langage a été créé notamment par Ken Thompson, en partie à l'origine de C, mais on sent également l'influence des langages de Wirth, Oberon notamment, dont les objectifs de simplicité extrême et de compilation rapide ont été au cœur du design. Les langages à typage dynamique ont également eu une influence sensible sur le langage. Go ressemble, au niveau du ressenti du développeur, à un intermédiaire entre les langages à typage statique et les langages à typage dynamique. Pour la gestion de la concurrence et du parallélisme, Erlang semble également avoir eu une influence.

Typé statiquement, le langage propose les types de base classiques (entiers, réels flottants, complexes, booléens, mais aussi les chaînes de caractères que C n'a toujours pas), mais aussi pointeurs, tableaux fixes, tableaux dynamiques (appelés slices, ou tranches en français), tableaux associatifs (appelés maps), fonctions (closures), et canaux (channels) qui permettent la communication entre processus légers. Il est également possible de créer des structures de données, appelés struct comme en C.

Il propose un certain nombre d'outils standards, facilitant la compilation, la maintenance et le déploiement des applications, l'un des plus appréciés étant go fmt, qui reformate automatiquement le code source de tout le projet courant selon les règles de style officielles. Ainsi, tous les projets écrits en Go partagent le même style.

C'est un langage très pragmatique, conçu pour utiliser des techniques éprouvées et offrir des outils de qualité aux développeurs. Les concepteurs ont choisi de tourner le dos à de nombreux résultats de la recherche dans le domaine des langages de programmation, au nom de la simplicité. Ainsi, pas de pattern-matching, pas de pointeurs non-nuls, pas de typage paramétrique (même si c'est susceptible de changer à l'avenir), ce qui est souvent reproché aux concepteurs.

Les goroutines

Les processus légers de Go (appelés goroutines) sont un des atouts de ce langage ; on sent une légère influence d'Erlang, dont un des buts est d'inciter à la création de nombreux processus légers ne partageant pas la mémoire. Ceci permet de profiter au maximum des capacités des architectures multi-cœurs, tout en palliant les défauts des approches de bas-niveau basées sur des threads/sémaphores/mutex, encore utilisés dans la plupart des langages majeurs. La communication entre goroutines se fait à l'aide des channels, qui fonctionnent comme des pipes UNIX dédiés à cet usage.

La programmation orientée objet

Go propose aussi un système de programmation orienté objet, mais réduit à sa plus simple expression :

  • un programme est découpé en paquetages (packages), et chaque paquetage indique ce qui est visible par les autres paquetages ou non (la distinction classique public/privé dans les autres langages),
  • les champs d'un struct peuvent donc être tous visibles, tous cachés, ou toute combinaison intermédiaire,
  • il est possible d'indiquer qu'une fonction donnée est une « méthode » s'appliquant à tel ou tel struct,
  • enfin, un système d'interface permet de regrouper, exactement comme en java des types proposant tous un certain nombre de méthodes.

Et c'est tout ! Pas d'héritage, pas de traits, pas de mixins, pas de classe à proprement parler, mais on se rend compte qu'on a déjà l'essentiel sans ça. Notamment, le mécanisme d'interface, très léger, couplé au système minimaliste d'inférence de type, permet d'obtenir quelque chose de très proche du duck typing, ce qui rend le langage très attirant pour les utilisateurs de langages à typage dynamique.

Le traitement des erreurs

Le mécanisme de traitement des erreurs en Go fait partie des points noirs les plus souvent reprochés au langage. L'idée des concepteurs est de ne pas recourir, sauf cas extrêmes, aux mécanismes habituels d'exceptions, qui permettent de faire « remonter » les erreurs de plusieurs niveaux lorsqu'elles se produisent, mais au contraire d'obliger les développeurs à les traiter le plus tôt possible, dès qu'elles se produisent.

Le langage utilise donc, comme C, un système basé sur l'analyse des valeurs de retour des fonctions pour savoir si une erreur s'est produite. Le mécanisme est quand même un peu plus élaboré qu'en C où il est aisé d'ignorer involontairement une erreur et de laisser s'exécuter un programme dans un état instable (par exemple, ignorer que malloc a échoué et renvoyé NULL). Sans entrer dans les détails, Go oblige à traiter la présence ou non d'erreur, mais il est possible dans certains cas de contourner volontairement cette contrainte et de laisser le programme continuer de s'exécuter dans un état incohérent.

Conclusion personnelle

À mon avis loin d'être exempt de défauts, Go me semble néanmoins intéressant. C'est un langage très simple, un des plus simples que j'ai pu rencontrer, et on peut être productif en quelques heures. Le langage est très normé, grâce à sa simplicité et aux outils de formatage, et il est très facile de lire du code écrit par d'autres développeurs, ce qui est un atout indéniable dans le cadre de grosses applications. Niveau performances, c'est acceptable (on est entre C++ et python, un peu moins rapide que Java et ça devrait s'améliorer avec le temps) et niveau productivité, on est clairement dans le haut du panier.

Je pense que ça vaut le coup d'apprendre ce langage. Comme il innove très peu (voire pas du tout) au niveau théorique, il n'a rien de très sexy, mais du coup on arrive très vite à faire des choses intéressantes avec. Quant à l'utiliser en production, c'est faisable, mais le langage est encore jeune (notamment le nombre de bibliothèques disponibles est encore limité), donc à chacun de peser le pour et le contre.

Aller plus loin

  • # Quid des gui

    Posté par  (site web personnel) . Évalué à 3.

    J'avais regardé et j'avais trouvé le langage plutôt plaisant. Il permet de faire ce que je fais d'habitude avec une certaine simplicité, souplesse et robustesse.

    La doc est un peu minimaliste mais on s'en sort.

    Par contre, je voulais en profiter pour faire un projet loisir avec une interface graphique et là, c'est la misère. C'est plus orienté système.

    Et vu la structure du langage, je vois pas bien comment ils vont me faire mon binding préféré, le goqt …

  • # Go continue à gagner un popularité?

    Posté par  . Évalué à 4.

    Faudrait que je teste ce langage un de ces jours quand même (il semble plutôt bien progresser au niveau popularité j’ai l’impression). Sinon, il n’y a que moi qui trouve que la mascotte est vraiment pas belle?

    P.-S.: petite coquille:

    […] aux développeur.

    Écrit en Bépo selon l’orthographe de 1990

  • # Laissez malloc tranquille !

    Posté par  . Évalué à 8.

    ignorer que malloc a échoué et renvoyé NULL

    Loin de moi l'envie de lancer le trollesque débat tester les valeur de retour : bien/pasbien

    De toute les fonctions standards qui sont susceptibles de rater, malloc est de loin la moins intéressante : malloc n'échoue jamais en pratique sur un OS décent, ensuite si malloc échoue, c'est qu'on est dans la merde, le savoir change pas grand chose, à part faire printf("va acheter de la RAM\n");exit(42);

    Please do not feed the trolls

    • [^] # Re: Laissez malloc tranquille !

      Posté par  . Évalué à 0.

      Toi tu n'as visiblement jamais eu a ecrire du code serveur ou tu recois une requete avec un champs decrivant la longueur et les donnees derriere.

      Tu t'amuserais a faire quoi si le champs longueur est tellement grand que ta requete d'allocation echoue ? Tu tues le serveur et toutes les connections qui sont en cours ?

      • [^] # Re: Laissez malloc tranquille !

        Posté par  . Évalué à 1.

        Je fais le malloc dans un process à part qui se fera tuer par le système si le malloc est trop grand.

        « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

        • [^] # Re: Laissez malloc tranquille !

          Posté par  . Évalué à 4.

          Un processus par requete ? Vive le design pourri qui ne monte pas en charge…

          • [^] # Re: Laissez malloc tranquille !

            Posté par  . Évalué à 9.

            C'est toi qui veut accepter n'importe quel longueur pour le fun. Je m'amuserais plutôt à ne pas traiter n'importe quel requête qui contient des données abbérante. Et c'est facile à vérifier, si tu dois faire un malloc(40Go) pour un champ de longeur, il faut se poser des questions.

            « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

            • [^] # Re: Laissez malloc tranquille !

              Posté par  . Évalué à 4.

              C'est quoi la longueur maximum alors ? Lorsque ton systeme est sous pression memoire, c'est quoi la longueur maximum que tu peux accepter ? Parce que t'auras pas besoin d'une allocation de 2Gb pour exploser ton allocation a ce moment la.

              Lorsque ton protocole te passe une collection de structures tu fais quoi ? Tu fais un comptage manuel de combien de memoire tu as dispo (bonne chance pour ca vu que les autres threads/processus changeront ca sous tes pieds) a chaque allocation pour savoir a quel point c'est trop ?

              Evidemment que non, la solution restante est de verifier la valeur de retour de malloc…

              • [^] # Re: Laissez malloc tranquille !

                Posté par  (Mastodon) . Évalué à 6.

                Moi, dans un code serveur, j'évite de faire des malloc, sauf quand c'est vraiment nécessaire. Dans le cas hypothétique que tu présentes, je ne vais pas allouer 2Gb parce que je reçois une grosse requête, je vais plutôt découper la requête en petit morceaux et traiter les morceaux les uns après les autres, éventuellement dans un buffer alloué statiquement ou sur la pile (comme ça, pas de malloc). Et si vraiment j'ai besoin d'avoir 2Gb, je sauvegarde le tout dans un fichier, toujours par petits morceaux et je vois ce que je peux en faire après.

                • [^] # Re: Laissez malloc tranquille !

                  Posté par  . Évalué à 2.

                  Eviter de faire des mallocs ?

                  En theorie c'est joli et je suis plutot d'accord, mais cela a ses limites. Deja la pile ne contiendra pas de buffer qui fasse plus que qqe dizaines de Kbs sous peine de te taper un stack overflow potentiellement. Ensuite tes buffers alloues statiquement, soit tu traites des petites requetes et c'est tout bon, soit tu gardes sous la main assez de gros buffers (genre 10Mb on dira) et la tu bouffes de la RAM pour rien le plus souvent.
                  Il va bien falloir que tu alloues a un moment ou un autre (t'as pas reserve assez de buffers, etc…), pas de miracle.

                  Ensuite pour le traitement pas petits morceaux… tout depend de ce que ton service fournit, si c'est faisable oui, si ca ne l'est pas, ben t'as pas le choix.

                  • [^] # Re: Laissez malloc tranquille !

                    Posté par  (Mastodon) . Évalué à 5.

                    En theorie c'est joli et je suis plutot d'accord, mais cela a ses limites.

                    Lesquelles ? J'ai déjà vu un décodeur MPEG4 avec zéro malloc, donc je me dis qu'en faisant attention, ça doit pouvoir se généraliser assez bien.

                    • [^] # Re: Laissez malloc tranquille !

                      Posté par  . Évalué à 1.

                      Tous les cas ou ta taille de bloc est "presque" aleatoire par exemple. Si tu ne sais pas d'avance quelle taille tu va devoir gerer, tu dois soit allouer dynamiquement, soit avoir un tas de buffers gardes de cote que tu n'utilises quasiment jamais et qui coutent sur le systeme.

                      • [^] # Re: Laissez malloc tranquille !

                        Posté par  . Évalué à 2.

                        soit avoir un tas de buffers gardes de cote que tu n'utilises quasiment jamais et qui coutent sur le systeme

                        Ce qui revient d'ailleurs à coder un malloc() du pauvre.
                        (marrant que le commentaire de pbpg soit moinssé à ce point alors qu'il a raison)

                        • [^] # Re: Laissez malloc tranquille !

                          Posté par  . Évalué à 3.

                          Dans la tradition boudhiste, il est dit que tes mauvaises actions font descendre ton karma.

                        • [^] # Commentaire supprimé

                          Posté par  . Évalué à 0. Dernière modification le 17 novembre 2013 à 20:10.

                          Ce commentaire a été supprimé par l’équipe de modération.

                          • [^] # Re: Laissez malloc tranquille !

                            Posté par  . Évalué à -1.

                            Oh mon dieu… Comment oses tu comparer du sucre syntaxique autour d'une allocation sur la stack avec ce don't on parle ?!?

                            Et lorsque tu dois creer des structures avec plusieurs buffers, tu vas les garder comment tes buffers quand la function qui a alloue ton buffer sur la stack termine ? Ah oui tu pourras pas vu qu'ils sont sur la stack !

                            Si ton thread est asynchrone et gere plusieurs requites tu fais comment ? Tu peux pas non plus vu que la stack est sequentielle et par thread.

                            Et je ne parles meme pas du probleme de stack overflow.

                            • [^] # Re: Laissez malloc tranquille !

                              Posté par  (site web personnel) . Évalué à 0.

                              ce don't on speak
                              I know just what you're saying
                              So please stop explaining
                              Don't tell me cause it hurts (no, no, no)

                              Hum. Oui donc sinon je suis assez d'accord sur ce que dit pbpg dans ce fil de commentaires et je n'ai pas grand chose de constructif à ajouter mais j'aime beaucoup cette typo.

                              pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.

                  • [^] # Commentaire supprimé

                    Posté par  . Évalué à 2.

                    Ce commentaire a été supprimé par l’équipe de modération.

                    • [^] # Re: Laissez malloc tranquille !

                      Posté par  . Évalué à 4.

                      Pour les serveurs, travailler par petits morceau, minimiser les allocations, ce sont de très très bonnes pratiques.

                      Personne ne dit le contraire, mais des fois tu n'as pas le choix. En plus ça n'est pas toujours vrai.
                      Déjà, si tu peux faire une opération en mémoire qui va aller vite, il ne faut surtout pas t'en priver. Donc faire un gros malloc et utiliser la méthode lente (avec étude par segment des données, tri du truc, traitement par lot etc.) seulement si le malloc échoue ça fait gagner un paquet de temps.
                      Ensuite certaine opérations (notamment les bitmap scan des bases de données, un gros map des familles, la décompression de certains formats d'image etc.) ne peuvent se faire facilement qu'en mémoire. Bon après il y a toujours des acrobaties - mais c'est en faisant les acrobaties que tu risques de te prendre des fuites de mémoires, une mauvaise maitrise de la mémoire utilisés et des DOS.

                      Très honnêtement la méthode qui consiste à tenter d'abord un calloc, puis en cas d'échec on tente le malloc, puis en cas d'échec on attend un peu et on retente un malloc et finalement on fait la méthode lente (ou on envoie un message utilisateur disant que là, c'est loupé), est parfaitement valide dans tout un tas de cas.

                      Après pour éviter que ca ne vire à la guerre nucléaire totale, il y a toujours les "limit" UNIX. Dans de nombreux cas c'est ça qui va faire filet de secours pour ton système (on est jamais à l'abri d'une fuite de mémoire à la con dans le programme d'à coté).

                      • [^] # Commentaire supprimé

                        Posté par  . Évalué à 1. Dernière modification le 14 novembre 2013 à 12:03.

                        Ce commentaire a été supprimé par l’équipe de modération.

                        • [^] # Re: Laissez malloc tranquille !

                          Posté par  . Évalué à 3.

                          Apparemment, je n'ai pas assez mis de gras, je dois le faire en capitale également ?

                          Tu as du mal lire. Tu dis que ça prévient, que ça évite pas mal de choses. Sous entendu il en reste d'autres qu'il faut traiter différemment.
                          Ce que je dis moi, c'est qu'il existe des cas (de plus en plus courant avec le cloud et autres anneries) dans lesquels ca va au contraire générer les problèmes dont tu parles. Si tu avais écris "dans la plupart des cas ca évite les fuites de mémoire" mon post tel qu'il est écrit n'aurait eu aucun intérêt. Mais ce ne pas ce que tu as écris.

                          De plus, ce que tu dis n'est pas valable pour la plus part des serveurs qui servent beaucoup de clients. C'est bien pour quelques clients qui demandent des gros traitements.

                          Pas forcément. Ce n'est pas valable pour les serveurs qui ont beaucoup de clients dont l'immense majorité va demander des traitements très rapides et non critiques. (Ce qui est le cas des serveurs web et des proxy en effet). Mais dans tous les autres cas, ça se discute. Dès qu'il y a des semaphores ou des mutex qui s'en mêlent ça devient assez rapidement rentable d'allouer de la mémoire et de faire le traitement directement en RAM avec une structure connue que de prendre le temps de classer, de morceler, d'analyser - avec le reste des processus qui attendent que quelqu'un veuille bien enlever le lock.

                          • [^] # Commentaire supprimé

                            Posté par  . Évalué à -4. Dernière modification le 14 novembre 2013 à 12:24.

                            Ce commentaire a été supprimé par l’équipe de modération.

                    • [^] # Re: Laissez malloc tranquille !

                      Posté par  . Évalué à -2.

                      J'ai 8M, par défaut, chez moi.

                      Et sur Windows c'est 1Mb… Dans un systeme avec plein de processus et/ou threads, ca commence a te couter pas mal et tu vas le reduire.

                      Tu ne réserves pas vraiment. Tu alloues sur le stack.

                      J'ai bien compris, mais quand tu fais ca dans une librairie, tu ne sais pas tout ce qu'il y a au dessus de toi sur la stack, resultat tu tend a etre conservateur pour eviter de te prendre un stack overflow.

                      Pour les serveurs, travailler par petits morceau, minimiser les allocations, ce sont de très très bonnes pratiques.

                      Tout a fait, quand c'est possible. Le truc est qu'il y a plein de cas ou tu n'as pas trop le choix parce que le probleme ne s'y prete pas.

                      • [^] # Commentaire supprimé

                        Posté par  . Évalué à 1.

                        Ce commentaire a été supprimé par l’équipe de modération.

                        • [^] # Re: Laissez malloc tranquille !

                          Posté par  . Évalué à -1.

                          Ben, non parce que cela n'est pas allouer tant que ce n'est pas accédé :/

                          Si tu utilises la stack pour tes buffers ca va justement etre alloue et rester alloue.

                          Pas de différence fondamentale avec un buffer overflow.

                          Mon dieu … Si il y a une difference fondamentale :

                          Un buffer overflow c'est une erreur de programmation, acceder a un buffer plus grand qu'il ne devrait etre, tu peux t'en premunir en codant proprement. Un stack overflow est qqe chose contre lequel tu ne peux pas te premunir, meme si tu as encore 2Gb de RAM libre ! Va lire la man page de la function alloca et regarde ce qu'elle dit en cas de stack overflow : comportement non determine, la joie !

        • [^] # Re: Laissez malloc tranquille !

          Posté par  (site web personnel) . Évalué à 10.

          Mauvaise stratégie, il n'y a rien qui te garantit que c'est le processus qui va faire le gros malloc qui va se faire tuer. D'ailleurs, en pratique, souvent, ce n'est pas le processus qu'on voudrait qui se fasse tuer mais un autre qui n'avait rien demandé à personne.

      • [^] # Re: Laissez malloc tranquille !

        Posté par  . Évalué à 1.

        Spontanément comme ça j'aurais tendance à ne pas faire ce que le client me dit de faire, j'ai bon ?

        Parce que si le client s'apprête à t'envoyer 1Go, tu alloue 1Go, ça passe ! YOUHOU ! Heu…

        Please do not feed the trolls

        • [^] # Re: Laissez malloc tranquille !

          Posté par  . Évalué à 2.

          Et si le client t'envoie 30Mb, que ton systeme est sous pression memoire temporairement mais peut quand meme gerer des requetes de moins de 20Mb tu fais quoi ? Tu exploses parce que c'est plus de 20Mb, tu coupes le service et coupe toutes les connections qui etaient en cours ?

      • [^] # Re: Laissez malloc tranquille !

        Posté par  (site web personnel) . Évalué à 5.

        Heu, dans ce cas là, on vérifie que la taille des données à allouer reste raisonnable avant de faire le malloc (ou équivalent).

        • [^] # Re: Laissez malloc tranquille !

          Posté par  . Évalué à 0.

          Mais c'est quoi "raisonnable" ? Tu ne sais pas quelle est la taille de ton plus gros chunk disponible dans l'espace memoire, tu ne sais pas si le systeme a du swap/ram physique dispo pour garantir ton chunk.

          Le seul moyen de savoir si tu as de la place pour ton alloc c'est de … faire l'alloc.

          • [^] # Re: Laissez malloc tranquille !

            Posté par  (site web personnel) . Évalué à 4.

            Le "raisonnable" dépend des cas. Ça peut être une valeur arbitraire. Par exemple, un serveur web comme nginx limite la taille de la requête d'un client à 1Mo (par défaut, c'est bien évidemment configurable).

            Une stratégie possible est de diviser la taille totale de la mémoire par le nombre maximum de client à gérer pour définir cette limite. Si on 8Go et que l'on se limite à un maximum de 1024 clients, en imposant une limite à 8Mo par client, on est tranquille.

            • [^] # Re: Laissez malloc tranquille !

              Posté par  . Évalué à 2.

              Et tu te retrouves avec une limite totalement artificielle qui t'empeche de gerer des requetes de taille tout a fait normale, toujours sans avoir aucune garantie que ton allocation fonctionnera car tu n'as aucun controle sur la pression memoire du systeme en entier (tu ne sais pas ce que le serveur contient d'autre) et peu sur la fragmentation de l'espace memoire de ton soft.

              Resultat, meme avec ta limite a 8Mo, tu as toujours des chances de planter.

              • [^] # Commentaire supprimé

                Posté par  . Évalué à 4. Dernière modification le 14 novembre 2013 à 11:33.

                Ce commentaire a été supprimé par l’équipe de modération.

                • [^] # Re: Laissez malloc tranquille !

                  Posté par  . Évalué à 1.

                  Ben non :/ C'est juste découpé en morceau et traité en morceau.

                  Mais de nouveau, c'est le cas uniquement si ton probleme se prete a etre traite en morceaux.

                  Peut-être chez toi. Mais pas chez moi.

                  Quand t'es le gars qui ecrit le soft, t'as aucun controle la dessus, t'es sense faire pour que cela marche dans la plupart des cas correctement.

                  ???

                  Selon la fragmentation de l'espace memoire du soft, t'as beau avoir 60Mb de libre, tu n'arriveras pas a faire une alloc de plus de 2Mb…

                  Et pour quoi donc avec morcellement ? On garantit juste que 1024 clients seront très bien servis ! Tant pis pour les autres. De toutes manières le système ne supportera pas mieux.

                  Ce sera vrai uniquement si tu prealloue 1024 blocs de 8Mb, resultat tu forces ton processus a avoir 8Gb alloues tout le temps, super…. (et evidemment en imaginant que ton probleme se prete au modele ou aucune autre allocation dynamique est necessaire)

                  • [^] # Re: Laissez malloc tranquille !

                    Posté par  . Évalué à 10.

                    Hé, psssst! pBpG ! Je te pertinente beaucoup sur ces fils de discussion, mais au risque de répéter ce que t'ont déjà dit d'autres gens plein de fois, steup, utilise la syntaxe de citation :

                    > [la citation]

                    [une ligne vide]

                    [ton texte]

                    Mes yeux te remercient d'avance ! :)

      • [^] # Re: Laissez malloc tranquille !

        Posté par  . Évalué à 3.

        C'est un pattern pas terrible si tu en arrive là. Soit tu essaie de faire une grosse allocation et c'est terriblement fragile, soit tu fait une allocation relativement petite et ton système n'est plus capable de faire grand chose.

        Si ton client veux travailler avec une grande quantité de données il va falloir lui demander de les découper comme c'est fait partout ailleurs. L'utilisation d'un pool de processus permet de donner au noyau plus de visibilité quant à la gestion de la mémoire.

        Pour ce qui est du OOM killer il s'activera de toute façon que l'on vérifie ou non le résultat du malloc() donc ça n'est pas vraiment à prendre en compte (à part s'il s'active après que le processus fautif se soit suicidé).

        Si on a vraiment besoin de faire de grosses allocations, il faudrait AMHA utiliser des huge pages et ça ne se gère pas de la même manière.

        Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

        • [^] # Re: Laissez malloc tranquille !

          Posté par  . Évalué à -4.

          Rappel : OOM Killer c'est specifique a Linux… Tous les OS ne traitent pas le manque de memoire de la meme maniere.

          Je veux bien que les tres grosses allocs soient a eviter, mais le truc est que 10 ou 20Mb c'est pas si enorme… Regarde les PDF d'aujourd'hui, il y en a plein qui font cette taille. Si ton serveur explose en vol a cause d'une alloc de 20Mb parce que t'es temporairement a court de RAM il y a quand meme un sacre probleme.

          Un pool de processus c'est toujours pourri au niveau du design, tu te tapes le cout de chaque processus a part le 1er (stack assignee au process, tous les buffers statiques, etc…) en extra. Tout ce que tu fais au final c'est accelerer le moment ou tu seras OOM vu que tu consommes plus, et tu perdras toujours des connections vu que c'est un pool, a moins de faire 1 process / connection mais la c'est tellement un desastre niveau architectural qu'il vaut mieux pas imaginer.

          • [^] # Re: Laissez malloc tranquille !

            Posté par  . Évalué à 2.

            Rappel : OOM Killer c'est specifique a Linux… Tous les OS ne traitent pas le manque de memoire de la meme maniere.

            Ça tombe bien j'ai dis qu'il fallait l'ignorer (windows fait quoi lorsqu'il n'a plus de mémoire ?).

            Regarde les PDF d'aujourd'hui, il y en a plein qui font cette taille. Si ton serveur explose en vol a cause d'une alloc de 20Mb parce que t'es temporairement a court de RAM il y a quand meme un sacre probleme.

            Et tu voudrais qu'on processus en traite des centaines ? (puisque tu refuse les pools de processus)

            et tu perdras toujours des connections vu que c'est un pool, a moins de faire 1 process / connection mais la c'est tellement un desastre niveau architectural qu'il vaut mieux pas imaginer.

            Si tu as un malloc() qui plante tu perdra quoi qu'il en soit des connexions quoi qu'il arrive.

            Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)

            • [^] # Re: Laissez malloc tranquille !

              Posté par  . Évalué à -2.

              Ça tombe bien j'ai dis qu'il fallait l'ignorer (windows fait quoi lorsqu'il n'a plus de mémoire ?).

              Tout depend de l'operation. Si c'est le noyau qui fait l'allocation et c'est pour un truc absolument critique, ben il finit en ecran bleu, pas le choix. Si c'est quoi que ce soit d'autre (kernel et truc pas critique, processus utilisateur…), le code gere le fait que l'allocation rate et continue. Pas de OOM killer du tout.

              Et tu voudrais qu'on processus en traite des centaines ? (puisque tu refuse les pools de processus)

              Si c'est un serveur (fait des conversions, extrait du texte, de l'edition en groupes, etc… que sais-je) oui. Quel interet d'avoir plusieurs processus identiques? Ca te coute en ressources et le service fournit est identique.

              Si tu as un malloc() qui plante tu perdra quoi qu'il en soit des connexions quoi qu'il arrive.

              Tu m'expliqueras comment. malloc retourne NULL, tu essaie de renvoyer une erreur au client, si ca ca rate, tu fermes le socket. Tu as perdu cette connection la, mais toutes les connections en cours sont toujours la.

          • [^] # Commentaire supprimé

            Posté par  . Évalué à 3.

            Ce commentaire a été supprimé par l’équipe de modération.

            • [^] # Re: Laissez malloc tranquille !

              Posté par  (site web personnel) . Évalué à 1.

              un mmap ? pas un sendfile() ou équivalent ?

              "La première sécurité est la liberté"

            • [^] # Re: Laissez malloc tranquille !

              Posté par  . Évalué à 5.

              Perso, je n'alloue rien pour un PDF. Je fais un mmap et je laisse l'OS faire son boulot.

              Je pige pas bien. mmap est utilisé en sous-main (avec brk) pour allouer la mémoire sous Linux. Ensuite, mmap peut échouer, et du coup tu dois tester la sortie en erreur.

              Note : je sais bien que tu veux dire que tu utilises mmap pour mapper le fichier PDF en mémoire. Sauf que, il serait aussi tout à fait envisageable que le PDF soit généré à la volée, et fasse effectivement ~20Mio…

              Dans tous les cas, ton mmap peut potentiellement échouer, et dans ce cas, il faut bien signaler au client qu'une erreur s'est produite. En quoi cela change-t-il d'une allocation mémoire qui échoue ?

            • [^] # Re: Laissez malloc tranquille !

              Posté par  . Évalué à -3.

              Si tu veux simplement lire le fichier PDF oui, mais quand tu as des operations a faire dessus (conversion, etc…) va bien falloir faire le parsing du PDF, stocker tes objets, etc…

            • [^] # [H.S.] Pluriel des acronymes anglais

              Posté par  . Évalué à 4.

              les OSes

              Vous dites vraiment «oèssiz»? Si oui, alors une partie est prononcée en français et l'autre en anglais, ou alors vous le prononcez complètement en anglais, dans tous les cas c'est bizarre; si non, on écrit «des OS» parce qu'en français on ne marque pas le pluriel des acronymes.

              Écrit en Bépo selon l’orthographe de 1990

        • [^] # Re: Laissez malloc tranquille !

          Posté par  . Évalué à 4.

          Si on a vraiment besoin de faire de grosses allocations, il faudrait AMHA utiliser des huge pages et ça ne se gère pas de la même manière.

          Deux remarques générales :

          1. Utiliser les huge pages ne change pas le fait que malloc rendra toujours une adresse valide sous Linux (allocation optimiste), et donc que la valeur de retour sera presque tout le temps inutile (mais pas à ignorer si tu veux que ton code soit portable — il existe d'autres systèmes qui allouent la mémoire avec une stratégie différente).
          2. Les huge pages sont utiles pour éviter la fragmentation mémoire et réduire les TLB miss. C'est tout (et en fait c'est déjà énorme pour un code qui cherche la haute performance et qui est memory bound). Ça ne joue pas sur l'allocation en elle-même.

          En ce qui concerne Linux en particulier, la façon dont les huge pages sont implémentées tiens du gros hack (on doit spécifier le nombre de grandes pages qu'on veut allouer au boot, pour s'assurer de la contiguïté de la mémoire physique), et c'est géré plus ou moins via les mêmes mécanismes que pour les segments de mémoire partagée (en tout cas c'était le cas il n'y a pas si longtemps).

          Pendant sa thèse, Alan Cox avait publié un article très bien sur les « superpages » et comment les allouer. Il avait fait ses tests sur Alpha avec FreeBSD. L'idée est de découper la mémoire virtuelle en utilisant la taille maximale des pages du système (sur x64 : 4Mio). Si la charge de la machine et le « profil » des programmes qui tourne dessus requièrent des allocations plus petites, une superpage est ensuite redécoupée en utilisant la taille de page directement inférieure à celle courante. Les différentes pages sont affectées aux pools pour chaque taille. Évidemment, le système doit essayer de recycler au maximum les pages de taille inférieure, pour limiter la fragmentation de la mémoire virtuelle. De même, si un ensemble de « petites » pages sont contiguës en mémoire, le système doit essayer de les « upgrader » vers le pool des pages de taille supérieure. Ce genre de méthode est très pratique sur les machines qui ont des tailles de page configurables (il y avait un microcode sur Alpha qui permettait de le faire; sur Itanium la taille des pages est arbitraire et configurable aussi; etc.).

    • [^] # Re: Laissez malloc tranquille !

      Posté par  . Évalué à 0.

      De toute les fonctions standards qui sont susceptibles de rater, malloc est de loin la moins intéressante : malloc n'échoue jamais en pratique sur un OS décent, ensuite si malloc échoue, c'est qu'on est dans la merde, le savoir change pas grand chose, à part faire printf("va acheter de la RAM\n");exit(42);

      Ben, c'est déjà pas mal d'arrêter le programme sur-le-champ avant d'aggraver la situation. Mais effectivement, il n'y a pas grand chose d'autre à faire.

      Sinon, ça arrive un échec de malloc, ça m'est arrivé il n'y a pas longtemps (mais c'était en plein stress-test).

    • [^] # Re: Laissez malloc tranquille !

      Posté par  . Évalué à 10.

      malloc n'échoue jamais en pratique sur un OS décent, ensuite si malloc échoue, c'est qu'on est dans la merde, le savoir change pas grand chose, à part faire printf("va acheter de la RAM\n");exit(42);

      Virtualisation, big data et fuite de mémoire d'une appli tierce sont dans un bateau. Qui est dans un autre univers. Parallèle au tien apparament. Et très éloigné.

      Sur mes serveurs j'ai plusieurs milliers de malloc qui ratent tous les jours. Je le vis très bien, mes applis aussi.

  • # Programmation orienté objet : non

    Posté par  (site web personnel) . Évalué à 10.

    Go propose aussi un système de programmation orienté objet, mais réduit à sa plus simple expression […]

    Non. Décidément, on affuble de POO ou de langage orienté objet tout et n'importe quoi.
    D'abord, ce n'est pas parce que tu rassembles des fonctions et des champs dans une structure que ça en fait de la POO. (Ni le fait d'associer une fonction à une structure ou à un type comme en Go.)
    Et les auteurs n'ont jamais jusqu'à présent qualifié leur langage d'orienté objet ni de l'avoir conçu pour pouvoir faire de la POO. Ils restent dans la programmation structurée mais empruntent des techniques actuelles tout en restant pragmatique ; je prendrais pour exemple les interfaces dans Go.

    • [^] # Re: Programmation orienté objet : non

      Posté par  . Évalué à 7.

      Pas faux.

      Le problème, c'est que tout le monde a une définition différente de ce qu'est la programmation objet, et que selon cette définition, tel ou tel langage sera ou non considéré comme "objet". Certains diront que Java n'est pas "orienté objet" parce qu'il n'a pas le dispatch multiple, que tout n'y est pas objet et qu'il est possible de ne pas cacher les variables d'instance. D'autre qu'Ada n'est pas objet, parce que (jusqu'à 2005 en tout cas) il n'avait pas la syntaxe objet.méthode(arguments). D'autres encore notent que python n'a pas de mécanisme d'encapsulation. Etc. Il n'y a guère que CLOS et Smalltalk qui semblent faire consensus.

      Dans le cas de Go, on a les mécanismes d'encapsulation, de polymorphisme, d'introspection et de fonctions attachées à des types, en pratique ça permet déjà de faire des choses.

      • [^] # Re: Programmation orienté objet : non

        Posté par  . Évalué à 1.

        J'imagine que ce qui fait la distinction pour lui est l'héritage, absent de Go.

      • [^] # Re: Programmation orienté objet : non

        Posté par  (site web personnel) . Évalué à 4.

        Pour moi, il n'y a en fait qu'une définition de la POO : celle qu'en a donnée son auteur, Alan Kay. Maintenant, dans les faits, il ne faut pas se cacher, il y a bien plusieurs formes de POO et desquelles, historiquement, nous pouvons en dessiner deux orientations :
        - la première, celle telle que définie par son auteur, Alan Kay, et qui est centrée avant tout sur le comportement,
        - l'autre, telle qu'elle a été perçue et évangélisée (en particulier par Ole-Johan Dahl et Kristen Nygaard (les auteurs de Simula) et leurs enfants spirituels), et dans laquelle l'approche est avant tout centrée sur la structuration ; une approche orientée classe. C'est cette approche qui est la plus en vogue.

        Ensuite, le multi-dispatching, la généricité, les éléments de syntaxe (comme objet.method()), et autres joyeusetés ne sont que des détails techniques d'un langage et ceux-ci ne sont pas l’apanage de langages dit orienté-objet. D'autres types de langages peuvent aussi les implémenter comme des langages fonctionnels ou impératifs structurés.

        Dans le cas de Go, on a les mécanismes d'encapsulation, de polymorphisme, d'introspection et de fonctions attachées à des types, en pratique ça permet déjà de faire des choses.

        Oui, je suis tout à fait d'accord et c'est ce qui fait, à mes yeux, avec le go-routines, tout l'intérêt de Go.

  • # interface avec autres lib en C ?

    Posté par  . Évalué à 4.

    Comment se lance un programme Go ? Est-il structuré en ELF ? Est-il compatible avec ldconfig ? Est-ce qu'il utilise la libc ou a-t-il sa propre libc ?
    Comment se fait l'interface d'un programme en Go avec des bibliothèques telles que libc ? ou d'autres bibliothèques écrites en C ?

    • [^] # Re: interface avec autres lib en C ?

      Posté par  (site web personnel) . Évalué à 7.

      Comment se lance un programme Go ?

      On lance le binaire compilé.

      Est-il structuré en ELF ?

      Oui, les binaires sont bien en ELF.

      Est-il compatible avec ldconfig ?

      Je ne suis pas sûr de comprendre la question. Les bibliothèques en go sont inclues dans le programme compilé (édition de liens statique).

      Est-ce qu'il utilise la libc ou a-t-il sa propre libc ?

      Il utilise la libc standard.

      Comment se fait l'interface d'un programme en Go avec des bibliothèques telles que libc ?

      On utilise les fonctions de la bibliothèque standard.

      ou d'autres bibliothèques écrites en C ?

      On utilise cgo. Cf http://blog.golang.org/c-go-cgo

      • [^] # Re: interface avec autres lib en C ?

        Posté par  . Évalué à 6.

        Il utilise la libc standard.
        

        Ce n'est pas le cas. Go n'utilise pas la libc car l'ABI go n'est pas la même que l'ABI C standard (c'est l'ABI de plan9). Il faut cgo pour lier à des bibliothèques C, et comme go doit être compilable sans cgo car cgo n'est pas supporté par tout, la lib standard de go n'utilise pas cgo partout.

        go a sa propre lib système, il y a du code assembleur pour effectuer les appels systèmes sur chaque plateforme sans passer par la libc. C'est d'ailleurs ce qui rend go un peu plus dur à porter que d'autres langages.

  • # Quelques problèmes fondamentaux

    Posté par  . Évalué à 10. Dernière modification le 17 novembre 2013 à 17:39.

    J'aime beaucoup go parce que sa syntaxe est claire et simple et que sa lib standard est cohérente et très fournie. Toutefois, je trouve que go a quelques problèmes fondamentaux cachés sous sa simplicité apparente.

    Le polymorphisme en est un. Le système de type n'est tout simplement pas assez puissant. L'utilisation de l'héritage pour fournir un sypertype pour un ensemble de types à une fonction ou à une structure de donnée polymorphe atteint vite ses limites. Je ne comprends pas l'obsession des développeurs à éviter toute autre forme de polymorphisme (générics, ou autres).

    Ces limites sont tellement présentes que les devs ont inclu des structures de données polymorphes dans le langage (maps, chans, et tableau) pour contourner les problèmes les plus courants. Toutefois, cela reste limité à ce que le langage supporte, et je trouve que go manque vite de flexibilité.

    J'ai par exemple eu l'occasion d'écrire une DB en go, en utilisant des arrays comme zone mémoire dans laquelle gérer l'allocation de blocs (pour ne pas avoir à utiliser le GC et les objets natifs, ce qui s'avère lent pour une DB). J'avais donc besoin d'écrire deux structures de données qui sont des listes de tableaux (pour éviter le realloc), l'une étant un tableau de bytes, l'autre un tableau d'entiers. Cela est impossible sans écrire le code deux fois, ou sans utiliser de hack pour sérialiser les entiers en tableau de byte. En effet, il est impossible d'allouer une slice de manière polymorphe. Il faut spécifier statiquement le type de la slice, mais on ne peut pas faire ça sans préprocesseur, parce qu'il n'y a pas de génériques/templates/autre chose. De même, il n'y a pas de supertype qui inclue les slices/arrays/maps. Il faut passer une "factory" qui alloue des nouveaux blocs, et on se retrouver à recopier le même code pour int et byte.

    j'ai beaucoup apprécié go au début, mais plus je l'ai utilisé et plus je l'ai trouvé bancal, et j'ai été très déçu par ce langage.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.