Mozilla a annoncé il y a quelques jours la disponibilité officielle de son langage de développement Rust. Cette première mouture finale représente un pas important pour l’éditeur, Rust étant notamment employé pour la création du moteur de rendu Servo, qui doit remplacer à terme Gecko dans Firefox.
Les performances de C/C++ avec des avantages de langages haut niveau
Rust est un langage de développement multiparadigme qui s’adresse en priorité à ceux qui manipulent le C et le C++. Globalement, l’objectif de Rust est de garder les performances de ces langages de bas niveau tout en ouvrant la voie à l’ensemble des apports des langages de plus haut niveau.
Comme l’indique Mozilla dans le billet d’annonce sur son blog, « Rust est un langage de programmation système qui fonctionne incroyablement vite, empêche presque toutes les erreurs de segmentation, et garantit la sécurité des threads ». Il est donc orienté objet, concurrentiel et typé sûr. Mozilla aimerait que les développeurs l’utilisent pour obtenir des applications et projets performants, tout en s’affranchissant autant que possible de toutes les erreurs classiques qui conduisent trop souvent à des soucis de sécurité.
Un rythme de développement calqué sur celui de Firefox
Nous avions déjà abordé Rust il y a deux ans quand Mozilla avait évoqué Servo. Ce moteur de rendu, développé avec le soutien de Samsung notamment, doit à terme remplacer Gecko au sein de Firefox. C’est en priorité pour ce projet que Rust a été créé, les ingénieurs ayant alors cherché un langage compilé qui maintenait les performances de C/C++ tout en permettant une autre approche de la sécurité.
L’arrivée de la version 1.0 signale en fait pour les intéressés qu’il n’y aura plus de changement profond qui pourrait casser la compatibilité. Les développeurs peuvent donc s’en servir sans craindre de voir des évolutions remettre en cause ce qui a été appris. D’ailleurs, le développement du langage fonctionne sur le même modèle que celui de Firefox. Aux côtés de la version 1.0 stable est donc apparue la mouture 1.1 bêta, tandis qu’un canal Nightly a également été mis en place. Toutes les versions seront mises à jour toutes les six semaines, ce qui promet donc une évolution rapide.
Cargo et crates.io pour gérer les bibliothèques et les dépendances
Parallèlement à la disponibilité de Rust, Mozilla a également introduit Cargo et crates.io. Le premier est un gestionnaire de paquets et de dépendances qui sera utilisé notamment pour ajouter simplement de nouvelles bibliothèques. Mais comme l'indique l’éditeur, « pour utiliser une dépendance, il faut d’abord la trouver ». C’est la mission de crates.io, le répertoire central des bibliothèques Rust. Le développeur pourra y trouver les créations des autres, ou publier les siennes.
Mozilla a de bons espoirs pour son langage et de grands projets. Les évolutions prévues sont déjà nombreuses, notamment sur la vitesse de compilation du code. Rust pourrait notamment intéresser ceux qui développent pour des plateformes multiples. Il dispose d’ailleurs de moyens multiples de communiquer avec des API, comme Alex Crichton, de chez Mozilla, l’expliquait le mois dernier au sujet du C.
Rust 1.0 peut être téléchargé depuis son site officiel. Mozilla précise bien que la version est stable et que le compilateur, en tant que tel, ne peut pas être utilisé pour gérer des fonctionnalités encore labellisées « instables ».
Commentaires (146)
Me suis jamais INtéressé à RUST. Mauvais souvenirs avec le C
" />
Mais bon, pourquoi pas jeter un oeil (ou les deux)
Justement, à priori, ça ne devrait pas être aussi casse-pied à programmer que C
" />
Je comprends mal. C’est un langage pour supplanter C/C++ ?
" />
Si c’est le cas, je vois mal comment ça pourrait arriver
ça ressemble fortement à ce qu’à présenter MS il y a quelques temps…
Sinon cela me fait aussi penser à True Detective.
intéressé, un peu curieux de voir à quel point c’est rapide et sûr. C++ c’est quand même bien amélioré question rapidité de codage avec les derniers /11 et /14, mais j’imagine bien qu’il est possible de faire mieux. Un peu surpris qu’il soit possible de faire aussi rapide que c++ sans jouer avec les pointeurs, j’attends des benchmarks :) (quelqu’un a testé ?)
Yay, moteur d’inférence de type, pas de typage statique déclaratif! \o/ Il est à peine temps que ça arrive ça, tiens, au lieu de toujours avoir le choix entre se faire ch*er avec des déclarations partout et être rapide, ou pouvoir écrire son code sans s’occuper de ça et être lent…
Marrant. On a l’impression que le résultat classe aussi en X les types de langage (compilé/interprété etc.).
C’est quand même utile pour un compilateur de savoir si tu traite du nombre et / ou autre chose.
Mais tant qu’on aura pas de vrais solution d’accompagnement (Tu sélectionnes tes 10 lignes et tu les tagges “integer”) et pas seulement un editeur de texte, bin voila.
pfff, çà peine sortis qu’il est déjà rouillé ce langage!
" />
Rust connaitra-t-il le même succès que Vala, Go ou Nim, … ?
/ironic
Thanks !
Go se porte tres bien. C’est juste une qu’une communauté autour d’un langage “bas niveau” ça se construit lentement, et ça sera le meme chose avec Rust qui apporte pourtant pas mal d’avantages.
+1 globalement, mais pas forcément dans les détails..
l’impact du code managé sur les perfs doit être plus ou moins constant en pourcentage, pas du tout en valeur absolue. Si le processeur est tel que tu n’as besoin que d’une fraction de ses perfs, alors effectivement tu te fous que le code soit managé ou pas. Si tu es dans une situation CPU-limited (super courant sur du mobile par exemple), alors les 10% que te bouffe le code managé fait mal aux fesses. C’est pas pour rien que les moteurs de jeux sont en c++, ou plus globalement les applications temps réel qui touchent à l’image par exemple.
Globalement je pense que ca converge de toute facons :
La grosse différence est surtout que dans un cas l’optimisation est offline (la compile) ou online (la VM), sachant que même ca peut être un peu flou (genre Android ART et compile AOT)
> brazomyna a écrit :
>
> Le problème de perf, c’est pas les pointeurs en soit, c’est la notion de “bound checking” qui va avec dans les langages qui proposent une abstraction complète de tout ce qui touche à l’accès mémoire. Et ce problème de perf en est de moins en moins un:
> - l’impact de ce genre de pratique sur la charge CPU est constant
> - la puissance dispo des CPU augmente régulièrement
>
> Donc en proportionnel, sans rien faire de spécial, juste en laissant faire le temps, l’impact relatif devient de plus en plus négligeable sur les perfs globales d’un soft.
>
> Même principe pour d’autres concepts. D’une façon générale, c’est pas pour rien que le managé est très utilisé aujourd’hui et l’était peu il y a 15 ans: tout simplement parce que l’overhead était important à l’époque, mais devient tellement négligeable qu’il devient de moins en moins justifiable de se passer de tout ce qu’apportent les langages managés.
>
> Restent un ou deux contre-exemples dans des domaines très spécifiques qui sont l’exception et non la règle ; et surtout les petits débats des Kevin dans la cours de récré. Ceux-là croient encore que la qualité d’un développeur se mesure au caractère bas-niveau du langage qu’il manipule.
>
>
Il y a quand même une bonne différence de perfs, on n’est pas prêts de passer sur Rust dans ma boîte dans ces conditions… Je suis surpris de voir c++ plus lent que c par contre
Go rencontre un petit succès tout de même. Fais un tour sur GitHub, le nombre de frameworks / librairies dispos et maintenues pour Go croit de jour en jour.
LOL ! T’as déjà regardé le code généré par un compilateur C++ et les trucs qu’il fait dans ton dos ? Quand c’est trop lent en C (compilé avec gcc en -O3) je passe en assembleur et j’ai un gain significatif ; mais en général C est satisfaisant et avec de l’expérience tu as une idée du code qui est créé.
Maintenant en fonction des contraintes, tel ou tel langage peut être plus adapté à une situation, mais pour du code très rapide c’est C + ASM et surtout un (des) très bon(s) développeur(s).
cépa vré !
" />
moua je sé ecrir en acen beurre
lé ho nivo cé pour les null
C’est clair que si tu écris strcmp() ou strlen() en C++ pur ça va être plus rapide que la libc GNU (hint : c’est écrit en assembleur). Principe de localité, SSE, … le nombre de trucs que l’on peut pervertir pour obtenir un gain de 30 - 50% avec des astuces monstrueuses, c’est le propre de l’être humain, accessoirement c’est rigolo.
ca dépend de la taille de la base de code.. Je ne doute pas que C puisse être super rapide si tu fais tout à la main (par définition, au pire tu prends ce que sort le compilo, au mieux tu améliore, donc globalement tu améliores forcément), mais en pratique tu as des limites en temps de développement et en nombre de personnes impliquées. C’est aussi ce à quoi Rust tente de répondre : faire du code rapide en temps limité, avec une équipe limitée. Les problèmes en temps infini, ce n’est pas super intéressant…
Du coup je suis curieux de ce benchmark : si c’est sur des trucs classiques (algos de tri, ..) alors le c++ peut très bien être aussi optimisé que le c, en y passant du temps (le c est plus ou moins inclus dans le c++, donc par définition tu peux faire aussi rapide) . Si ce n’est pas sur des trucs si classiques que ca, avec une grosse base de code, alors je suis curieux de voir les détails.
ca dépend complètement de ton application, le fait de se foutre des perfs. Si la valeur ajoutée de ta boîte est dans une fonction cpu-limited ou power-limited, alors les langages tels que le c++ ont tout leur sens. Dire que c’est marginal comme domaine, c’est un peu rapide… Certains domaines n’ont pas de middleware qui font le sale boulot, comme unity, et dans ce cas il n’y a pas le choix, il faut mettre les mains dans le cambouis. Il faut de tout pour faire un monde :)
Ouais bah le poisson il a été punit il doit écrire qu’en VB.NET au boulot, et ça l’ennui.
" />
Recherche dans un Btree (un red black tree), en C : indice (durée) 1, en ASM : 0,60 en utilisant en particulier la mise en cache (prefetcht0, prefetchnta), l’optimisation de l’anticipation de saut, l’alignement de boucle pour le décodeur d’instruction, …
J’ai juste 300 lignes d’assembleur pour un total de 23000 lignes (essentiellement en C) dans mon appli, certes ça coûte très cher à écrire mais au final ça le vaut largement. Maintenant il y a aussi d’autres aspects : conception en bottom-up, tests intensifs en particulier profiling mais bon quand il faut gérer plus de 4.10^9 objets complexes il faut aussi y mettre les moyens.
Oui, l’assembleur n’est pas portable, c’est un choix qui dépend de l’application et des contraintes. Maintenant reste à savoir s’il faut mettre en avant le confort (tout relatif) du développeur ou la performance d’une application dans un contexte donné.
S’il propose les mêmes performances tout en étant plus simple à écrire, la réponse à ta question est évidente.
Le C/C++ sont des plaies, il faut être très rigoureux dans son écriture et il faut faire soi même des choses qu’un bon compilation/machine virtuelle pourraient très bien faire tout seuls. En contrepartie ils n’y a pas mieux pour maîtriser son application au poil et pour les performances.
Au moins avec ça plus de soucis pour sortir des RUSTines
" />
Je pense que le passage au C++ permet d’aller plus vite pour développer. Je ne suis pas sûr que les compilateurs produisent du code machine qui soit significativement plus performant pour le C++ que pour le C.
Le seul projet sur lequel j’ai pu bosser avait des templates dans tous les sens. Tu te retrouves à modifier 15 fichiers pour rajouter une pauvre fonction quelque part. C’était probablement pas un bon exemple de beau code C++.
Après je n’ai jamais vraiment travaillé un projet là dessus, je dis ça juste avec mon expérience “de débutant”. Ce n’est pas un langage facile à appréhender je trouve, contrairement à d’autres langages comme le Python, qui non seulement est très simple mais propose un nombre de libs incroyable.
Tu dis des choses qui étaient vraies dans les années 90, beaucoup moins maintenant.
Par exemple, entre C et C++, le code C++, à niveau d’abstraction égal (même si cette notion est toujours subjective), est plus rapide que le code C. La comparaison classique (c’est un cas d’école en fait) entre qsort() et std::sort le montre aisément : un appel de fonction via pointeur contre un appel inliné : qsort() perd à tous les coups. En général, les benchmarks qui donnent C plus rapides que C++ s’expliquent par la naïveté du code C++ testé.
Pour l’assembleur, j’étais tombé sur une présentation (je ne la retrouve plus, j’aurais mis le lien sinon) qui expliquait comment écrire du C++ optimisable. Le type comparait, notamment, comment il avait remplacé ~200 lignes d’assembleur dans une lib de décodage vidéo (je crois que c’était ffmpeg) par 5 lignes de C++, et comment les perfs s’étaient améliorées en conséquences (le code asm était écrit pour des processeurs anciens, sur un processeur moderne il était moins efficace que celui généré par gcc). Il avait d’abord optimisé le code ASM en question, mais même sa version, plus efficace que le code initial, l’était moins que celle générée par gcc.
Après, tout est bien sûr question de mesures et de cas particuliers. Quand on en est à ce niveau d’optimisation, la seule vérité c’est le profiling.
Dépend des cas, justement parce que les templates permettent des optimisations assez bourrinnes (l’exemple typique c’est std::sort VS qsort <- grillé par @white_tentacle xD). Sans compter qu’un code plus facile à lire c’est aussi un code plus facile à optimiser si cette facilité n’est due pas à un manque d’expressivité.
Quant à ta remarque sur la complexité d’apprentissage de C++, c’est principalement dû au fait que les enseignements de ce langage se font à la mode historique (du C avec des classes) alors que d’une part la gestion des ressources dans un langage à exception, ça se fait pas manuellement si on n’est pas maso (en C++ le RAII, ça sauve des vies) et que d’autre part, il est très facile d’écrire en C++ avec une approche moderne comme celle qu’introduisent les dernières normes.
On apprend le C/C++ dans beaucoup de cours d’informatique et c’est ultra-implanter dans beaucoup de milieux.
La tâche s’annonce rude.
Vive le COBOL
" />
Parti très très loin ==> []
Merci, c’est intéressant. Maintenant entre l’inline et l’appel de fonction c’est pas un secret, d’ailleurs c’est un gros reproche que l’on peut faire aux TMV (tables de méthodes virtuelles) en C++, non ?
Donc, voici le code C, pas vraiment subtil, de recherche dans un Btree :
extern inline sw_item_t * sw_rb_tree_search (sw_rb_tree_t * tree, sw_item_t * item)
{
register sw_rb_node_t * node ;
int cc ;
node = tree->root ;
while (node)
{
cc = (* tree->cmp) (& node->item, item) ;
if (! cc)
return & node->item ;
if (cc < 0)
node = node->links [SW_RIGHT] ;
else
node = node->links [SW_LEFT] ;
}
return NULL ;
}
(Note : c’est en inline quand même, alors qu’en assembleur il y a le coût de l’appel de fonction mais négligeable par rapport au gain apporté). Si en C++ on peut faire mieux, ça m’intéresse mais comme j’ai aussi ma version assembleur, j’en doute…
Ah ben en lisant les commentaires, je vois que HarmattanBlow t’a déjà répondu ce que j’allais répondre.
" />
" />
J’ajoute quand même un truc: l’inférence de type est super-intéressante aussi quand ça ne marche pas. Ca paraît bizarre dit comme ça, mais j’avais vu un article sur le Web - il y a longtemps, je n’ai plus la référence - qui montrait le moteur d’inférence de types de OCaml détecter… une boucle infinie dans le code. En gros, on s’attendait à un type de retour donné, et celui inféré par le compilo n’était pas celui attendu. C’était à cause d’un cas pas/mal traité qui faisait partir le programme en vrille, et le moteur d’inférence de type l’avait détecté. Malgré sa prédominance un peu partout, quand on creuse un peu, le typage statique déclaratif n’a vraiment pas beaucoup d’avantage en fait, à part pour celui qui écrit le compilo.
Ah mais je ne suis pas contre Python, au contraire, je l’utilise beaucoup. Comme je le disais plus tôt, il faut de tout pour faire un monde, ca dépend vraiment des applications cherchées.
@brazomyna : tu y gagnerais quand même à voir ce qu’il se passe à l’extérieur de ton secteur d’activité.. “1% de code réellement contraint par le temps réel”, c’est assez risible pour le coup, je ne sais même pas si ca vaut le coup de réagir.. Je bosse ici, et le C++ est un peu utile par exemple, alors que la finalité est relativement simple / grand public. On est nombreux dans ce cas… (le code était initialement en C#, encore utilisé parfois pour prototyper, la différence de perfs avec C++ doit être dans les 10x et on est contraints par le CPU dans pas mal de scénarios…)
le code c++ serait quasi-exactement le même évidemment..
La première chose qui va être mieux en C++, c’est l’appel à cmp via pointeur de fonction qui va être inliné (ton btree va être paramétré par ton type, pas besoin de pointeur de fonction à ce niveau là).
Sinon, plutôt que d’implémenter toi-même une version améliorée, je t’invite à comparer les perfs de ton code avec celles de std::map (qui fournit un btree red/black). Si ton code fait mieux, je te tire mon chapeau : ça veut dire qu’à minima tu maîtrise bien ce que tu fais :).
J’ai parlé de ‘finalité’ grand public, pour être précis.. Et je maintiens, tout le monde ne peut pas se reposer sur un Unity, ca n’existe pas dans tous les domaines ou ca peut ne pas coller avec le business model. Exemple trivial qui explose tes 1% : l’écrasante majorité des applis iPhone était codée jusqu’il y peu en objective-c, un langage.. compilé. Ca représente du monde, iOS
Autre exemple
Désolé, je suis resté à C++ 1.0, en particulier les templates sont encore pires que le préprocesseur et cela a contribué à mon dégoût pour ce langage et en particulier pour les libs. Maintenant « inliner » la fonction de comparaison c’est du gagne petit comparé au principe de localité (en gros maintenir les données utiles en cache L1/L2/L3).
Sur mon application, par rapport à ce qui existe, j’ai un gain de 20, donc j’imagine que le travail de conception et d’optimisation n’a pas été inutile, mais en même temps quand on arrive à dépasser 64 Go de mémoire utilisée (physique et swap) on cherche vraiment la petite bête dès le début, d’où une conception en bottom-up. Maintenant, au risque de me répéter, tout dépend de l’application et des contraintes.
Une gestion mémoire semi-automatisée ? Avec les shared_ptr, elle est totalement automatique. Des itérateurs de 50 caractères ? “auto” : 4 lettres. 4, c’est beaucoup moins que 50. Pour le reste, ce n’est pas très clair de quoi tu veux parler, mais je suis sûr que le C++ le fait très bien. Bref, tu ne sais pas de quoi tu parles.
Rust est fait pour être un compromis entre sûreté, performance, facilité d’écrire du code. Donc quelque soit un aspect, tu trouveras à critiquer : c’est le principe d’un compromis.
Si tu ne veux pas de compromis, tu choisis C++. Mais l’analyse statique de code C++, c’est un défi énorme.
Mozilla souhaite utiliser Rust pour son moteur de rendu html. Et les perfs de Rust sont suffisante pour ce point. C’est nettement mieux que tout ce qu’on nous a vendu comme alternatives à C++ pour l’instant…
Okay, soit, tout n’est pas automatisé, il faut réfléchir et utilisée alternativement shared_ptr et weak_ptr. La raison est simple, le tout automatisé mène à des fuites mémoires contre lesquelles tu ne peux rien faire (sauf attendre une correction de ta VM / ton compilateur) alors que si tu réfléchis, tu peux être bien plus performant. Quant à auto, il est couramment utilisé pour les itérateurs, chose à laquelle je répondais. Le C++ est un langage typé, pour le meilleur, donc auto ne doit pas être utilisé à tout bout de champs… Bref, tu crois tout connaître, ton idée sur la question est la meilleure, et tu le montres de manière ostentatoire, bravo
" />.
« Pour le reste, ce n’est pas très clair de quoi tu veux parler, mais je suis sûr que le C++ le fait très bien. Bref, tu ne sais pas de quoi tu parles. »
" />
Il te montre juste que si, il sait mieux que toi de quoi il parle… Les attaques ad hominem c’est pas bien
Des frameworks, librairies et autres bindings c’est bien. Mais pour construire quelle genre d’application, au final ?
Même si je suis un peu à la rue n’utilisant principalement que le C# vu que j’ai pas besoin de grosses perf … Je trouve cette discussion plutôt intéressante même si un peu agressive par moment.
Je viens quand même de découvrir qu’en survolant “var” dans mon code, il me donnait le type qui allait être interprété, c’est plutôt intéressant !
Pour ce qui est du C/C++, je trouve ça assez imbuvable. Quand on compare au java/C# on en est quand même loin ! Alors certe ce n’est pas optimisé, et pas vraiment optimisable du fait de leur fonctionnement, mais c’est quand même bien plus facile à lire et plus simple à écrire.
Pour revenir à la base, ce langage à l’air intéressant comme l’a été Go à sa sortie, ou d’autres encore … Mais force est de constater qu’ils n’ont pas vraiment percés. La présence d’écosystème à bien aidé les langages “récent” comme objective-C, java (pour android notamment, même si ça marchait bien avant ça), VB/C# .NET (windows) pour se trouver un public.
C’est sûr que ça se fera pas un en jour. Mais ça n’empêche pas que l’objectif soit de l’ordre du possible, si le langage lui même est intéressant bien sûr. Notamment s’il est simple à utiliser.
Le problème c’est que dans les environnements “contraints” tu n’as pas toujours accès à un compilateur qui suit la dernière norme.
Maintenant si ce que tu dis est vrai, j’aimerais bien avoir un tuto qui couvre directement le C++ “moderne”. J’en suis effectivement resté au C++ “surcouche de C”, en sachant que le C lui même ne me convenait pas.
Pour ceux qui aime les chifre.
The current supported properties allow Servo to be mostly operational on
static sites like Wikipedia and GitHub, with a surprisingly small code
footprint. It has only about 126K lines of Rust code, and the Rust compiler and libraries are about 360K lines.
For comparison, in 2014 Blink had about 700K lines of C++ code, and
WebKit had around 1.3M lines, including platform specific code.
Faudr ajuste que Mozilla le documente correctement et ne l’abandonne pas au bout de quelques années, comme ils ont fait avec XPFE.
Merci !
Merci !
Commentaires passionnés et très intéressant !
Sinon j’avais vu passé ces 2 lien sur l’état actuel de la compilation statique et dynamique :http://www.emulators.com/docs/nx38_staticopt.htm
http://www.emulators.com/docs/nx39_dynopt.htm
Pourquoi ca serait le cas ? Le gros avantage est que Mozilla l’utilise pour son prochain moteur de rendu, Servo. Ce qui tire le langage et la commu vers le haut, sachant qu’un moteur de rendu avec tous les specs HTML5/CSS, c’est pas rien.
Honnêtement, Rust a de bonnes chances d’être intéressant dans le futur.
Le C colle au système / architecture avec un niveau d’abstraction suffisant pour la portabilité - quand cela est souhaité -, on peut faire avec du code de bootstrap de quelques octets sans connaître l’assembleur du processeur cible !
Mais bon c’est vrai qu’il n’y a pas de collecteur d’ordures (GC) d’intégré et qu’il faut savoir ce que l’on fait, mais c’est un métier aussi, on a tendance à l’oublier.
Docker par exemple est programmé en Go. Mais aussi le serveur de DL de Google aussi (dl.google.com), gogs (un gitlab like), etc, etc. Voirhttp://en.m.wikipedia.org/wiki/Go_(programming_language) section “Notable users”
L’intérêt est énorme. Je t’ai retrouvé un article sympa sur le sujet:http://blog.iron.io/2013/03/how-we-went-from-30-servers-to-2-go.html?m=1 :)
@eb303 - @HarmattanBlow
Bin en fait j’en parlais dans un sens large. Plus tu te rapproches de la machine mieux c’est de savoir l’avance et accessoirement de le rendre statique
L’exemple tout bête étant le programme qui modifie le type d’une variable en cours de route sur condition (quand c’est permis). Le compilateur n’a pas vraiment le choix que de produire du code un peu plus “générique” permettant de gérer les deux cas. Bon pas exactement en fait, il duplique mais vous aurez compris. Donc de toute façons couteux à tous niveaux (RAM/temps d’exec) mais il n’a pas trop le choix. Et plus ca monte en niveau (language) plus la syntaxe est flexible et plus le compilateur doit réfléchir et faire des concessions.
Le plus drôle étant qu’en assembleur on s’en fout un peu. On voit tout comme une donnée dans de la RAM et c’est le sens qu’on décide de lui donner a ce moment là qui compte, ou même comment on décide de la lire… Code gé né ré… la la la la la…. la la la la la…. (avec la musique et les papillons autour).
Bref, oui l’inférence c’est bien mais pas ultime a mon sens.
Sinon j’ai un projet qui me titille le bulbe depuis un moment et j’ai déjà écrit pas mal. Y’a des ASM boys motivés dans la salle ?
En fait je parle pas de Rust en particulier mais de tous les langages (et la liste est longue) et de leurs fumant problèmes (que tu décris aussi) versus le compilateur. Du gros , demi gros plus que du pointu.
Je pense que tout le monde a un peu raison.
Pour ma part, je dirais qu’il faut utiliser un outil pour ce qu’il fait très bien.
C/C++ n’a jamais été le meilleur langage pour faire de l’abstraction, pour pondre un programme rapidement ou pour avoir la dernière “feature” à la mode.
Mais c’est juste le top du top quand on veut un meilleur contrôle sur ce qu’on fait pour obtenir les meilleures performances.
Peut-on créer des interfaces graphiques avec Rust ?
Hum… pour le côté pro et intérêt c’est justement pour cela que c’est fait. T’as un programme qui met 81 heures à s’exécuter et un autre qui met 3h45, qu’est ce que tu préfères déployer chez un client (surtout si ça implique un déplacement et que le programme peut se casser la gueule si la machine du client n’est pas suffisamment musclée et refroidie) ?
Sur 23000 lignes de code, j’ai 300 lignes d’assembleur, tout le reste en C ; certes coder en assembleur c’est pas très productif surtout avec le temps passé à faire du profiling sur différents types de processeur, mais ce n’est pas significatif alors que le gain lui, est nettement perceptible.
Sur l’aspect bug, vu la quantité de données, le nombre de threads, de sections critiques, les pré-conditions et post-conditions et invariants, je vais être prétentieux mais le code est extrêmement fiable, ce n’est pas que du fait de l’outil mais de celui qui l’utilise, on a tendance à l’oublier.
Quant à utiliser une machine beaucoup plus puissante c’est aussi prévu mais ça viendra en plus. La petite différence avec un « bon » chef de projet, c’est que l’objectif n’est pas de pouvoir dire « j’ai tenu les délais et suis dans le budget alloué », mais plutôt d’innover et de rendre possibles de nouvelles choses. Ça se passe aussi (pas assez) comme ça dans le monde pro.
Bon, il y a certains aspects qui ne sont pas suffisamment explicites et c’est probablement de ma faute. Déjà je précise que mon patron c’est moi et que donc j’ai aussi en tête les contraintes commerciales.
Les 2100% de gain par rapport à ce qui existe ne sont pas le seul fait de l’optimisation du code, mais avant tout de la conception, de l’architecture et le choix du bottom-up, tout cela est cohérent et permet de mettre un tour de vis sur l’optimisation parce qu’en bottom-up on commence par les tests unitaires - moment privilégié pour optimiser - et surtout ne plus avoir à se poser des questions après parce que ça rame.
Pour l’assembleur, certes, la portabilité en prend un coup, mais déjà des contraintes impliquent de travailler en 64 bits et par ailleurs une version strictement C du code assembleur peut être activée en recompilant. Simplement c’est un plus qui n’a pas coûté trop cher et qui apporte réellement quelque chose de perceptible.
Sur les bugs j’avais prévenu ;-) il y a surtout beaucoup de rigueur et des tests unitaires (encore une fois en bottom-up c’est presque par construction) ; bien sûr que j’ai eu des core dumps et que j’ai passé du temps dans des débugueurs, mais pas tant que ça par rapport à d’autres projets parce que je me prends pas d’un seul coup toutes les couches à la fois. Sur un jeu d’essai ridicule (moins de 0,05% des données à traiter) Valgrind dit ça :
==6199== HEAP SUMMARY:
==6199== in use at exit: 0 bytes in 0 blocks
==6199== total heap usage: 1,813,792 allocs, 1,813,792 frees, 786,799,125 bytes allocated
==6199==
==6199== All heap blocks were freed – no leaks are possible
Pourtant c’est du C et de l’assembleur avec des pointeurs partout et on peut quand même faire des choses très propres avec.
Dans ce projet il ne s’agit pas simplement d’ajouter de la valeur, mais de créer de la valeur (en mode rupture), donc l’approche projet type corporate bullshit m’indiffère. Question d’objectif.
Avec un lien ça aide, donc le voici RAII. Du coup je réalise que je fais du RAII dans mon code C mais ça s’appelle un pool et il y a aussi des destructeurs associés, donc le côté killer feature en tant que propriété intrinsèque et exclusive de C++ m’échappe.
(edit)Argh : affreuse faute(/edit)
Désolé mais je ne programme pas comme ça en C, chez moi ça donne ça :
FILE f1 = NULL , f2 = NULL;
pool = alloc_pool (POOL_DEFAULT) ;
if (! pool)
return -1 ;
f1 = fopen (“blabla.txt”, “r”) ;
f2 = fopen (“blabla2.txt”, “r”) ;
pool_push_dtor (pool, close, (void *) f1) ;
pool_push_dtor (pool, close, (void *) f2) ;
res = …
// Erreur ou pas, on libère toutes les ressources qui sont dans la portée et associées au pool
reset_pool (pool) ;
free (pool) ;
return res ;
Un seul point de sortie (sauf erreur triviale détectée avant l’allocation de ressource) et un minimum de code explicite, il faut juste un peu de rigueur, mais nul besoin d’empiler des gotos, et dans le pool on peut mettre bien sûr la mémoire allouée mais aussi des fonctions spécifiques appelées avec un pointeur sur le contexte.
Et tu ne t’affranchis pas du « single exit » car il faut appeler tes destructeurs explicitement.
Question conne : pool_push_dtor ne peut pas échouer ? (pas d’allocation dynamique dedans, tu alloues par défaut suffisamment d’espace pour X destructeurs ?)
Pas exactement dans la mesure où le pool prend en charge nativement les allocations mémoires, j’ai juste ajouté la possibilité d’enregistrer dans la foulée des destructeurs pour faire des choses plus spécifiques si besoin est. Après c’est un appel effectivement explicite, mais il n’y a pas à gérer de multiples points de sortie donc à l’usage ce n’est pas franchement contraignant.
Enfin, pour l’allocation mémoire, contrairement à un compilateur qui ferait automatiquement des delete unitaires sur les objets, je travaille sur des blocs de 40 Mo ou de 16 Mo ce qui fait que je n’ai pas à faire une myriade d’appels systèmes sous mutex quand je détruis un pool, mine de rien ça se sent dans un programme qui fait des milliards d’allocations / désallocations.
Bonne question. Toute allocation mémoire dans le pool est testée au niveau le plus bas et donne lieu à fatal(), pas de récupération d’erreur possible, mais j’ai un mécanisme de régulation de la consommation mémoire avec seuil qui fait que quand la queue principale (en fait c’est plus compliqué) est trop remplie à mon goût, la production de données est interrompue le temps que la queue se vide.
Donc push_pull_dtor() alloue une cellule de liste chaînée dans le pool et peut très bien échouer mais comme, généralement j’arrête de continuer d’allouer de la mémoire lorsque j’ai atteint 20 Go (sur 32 Go + 32 Go de swap) et que j’attends de pouvoir recycler la mémoire qui passe en free list, ce cas de figure ne s’est jamais présenté.
Pour l’aspect explicite, ça demande un peu de rigueur, mais c’est vrai de chaque ligne de code, non ;-) ?
En tout cas, c’est intéressant, je n’ai jamais rencontré de code C qui mette cette technique en avant. La plupart que j’ai vus, quand ils géraient à peu près correctement les erreurs, avaient recours au goto cleanup.
À vrai dire moi non plus ! Le besoin est né parce que j’avais besoin de fiabilité et que malloc() / free() ne me convenaient pas et comme l’outil est permissif, l’implémentation était facile. Après j’ai ajouté des fioritures comme la possibilité d’enregistrer des destructeurs, non pas que je rechigne à utiliser des gotos (je fais même pire : setjmp() / longjmp()
" />), mais plutôt pour créer une sémantique au dessus de C qui me convienne pour mon application.
Maintenant, je ne vais pas prétendre que c’est la panacée et que c’est le truc qui va sauver des chatons, mais dans mon cas j’arrive à un bon résultat, le code est plutôt propre et surtout très fiable, au final c’est ce qui compte et si ça fait fumer les processeurs, c’est encore mieux !
Vous connaissez un bon éditeur pour apprendre le rust ? ( j’aimerais changer d’air car j’utilise depuis longtemps vim )
Pour le moment aucun éditeur n’est au poil, Mais il y a des plugin qui permettent d’avoir la gestion de la coloration syntaxique et parfois un support partiel de l’auto-completion pour pas mal d’éditeurs/IDE.
Je cite ceux qui me reviennent en tête mais il doit y en avoir d’autres :
appellerons-nous les correctifs rust-in ?