Rust est un langage de programmation conçu pour répondre aux problématiques modernes des gros logiciels clients et serveurs utilisant Internet, en particulier la sécurité, le contrôle de la mémoire et la parallélisation.
Comme le rappelle la rétrospective 2014, Rust est un sujet qui a été beaucoup traité l’année précédente. N’oublions pas non plus l’expérimentation avec Rust et ibus qui a fait l’objet d’une dépêche en octobre dernier.
Avec un peu de retard par rapport au communiqué lors de la sortie de la version 0.12, mais comme annoncé le 12 décembre, c'est près de 3 ans après la version 0.1 que l'équipe de Rust publie la version alpha de la version 1.0 du langage ce 9 janvier.
Ça y est, Rust 1.0 alpha est sorti ! Cela signifie que le langage et les bibliothèques ne recevront plus de changements majeurs.
Selon le tableau de bord de stabilité du projet, la bibliothèque standard a désormais 44% de code marqué stable (c’est-à-dire dont l’API ne changera pas) et 52% non stable (2% non marqué). Cela montre une très grande progression par rapport à la dernière version d'octobre 2014 où le code stable représentait seulement 2%, le non stable 12% et 77% pour l'expérimentale, le reste étant déprécié ou non marqué.
Principaux changements
Il y a plus de 2400 modifications, incluant les corrections de bogues, dans cette version alpha, l'ensemble des changements est fourni dans les notes de version.
Le travail a porté principalement sur deux modules : gestion des chemins de fichiers et entrées-sorties. Plusieurs fonctionnalités ont été implémentées dans le langage et la bibliothèque standard. Dans le langage ont été ajoutés la gestion des types de taille dynamique : les « multidispatch traits ». Les conventions de codage ont été appliquées dans la bibliothèque standard.
Les types à taille dynamique (DSTs pour Dynamically-sized types) sont des types dont la taille est fixe mais inconnue à la compilation. Ils souffraient de grosses limitations dans les précédentes versions de Rust, ils sont maintenant largement intégrés dans le langage.
Les types int
et uint
(les équivalents Rust de intptr_t
et uintptr_t
en C++) ont été déclarés obsolètes en faveur des nouveaux types isize
et usize
. Ce renommage a été fait dans le but d’encourager l’utilisation des types à taille fixe (actuellement i8
, i16
, i32
et i64
) pour assurer un fonctionnement cohérent entre différentes plateformes et prendre moins de mémoire. Les noms int
et uint
pouvaient faire croire à ceux venant du C/C++ qu'il s'agissait des types "par défaut" de Rust.Ce n'est pas le cas: i32
est le type par défaut pour les entiers (f64
pour les flottants), tandisque int
et uint
seront totalement supprimés d’ici la bêta. Plus d’infos
Une clause where
a été ajoutée pour faciliter la déclaration des contraintes de type lors de la déclaration de traits. Pour le développeur, le changement le plus visible est :
impl<K:Hash+Eq,V> HashMap<K, V> { […] }
// qui devient
impl<K,V> HashMap<K, V>
where K : Hash + Eq { […] }
Cela a également permis la suppression de plusieurs traits de la bibliothèque standard, ainsi que quelques autres simplifications bienvenues.
Le système de macro a été largement amélioré pour le préparer à la sortie de la 1.0. C’est un travail de nettoyage, d’arrondissage des angles, d’amélioration de la syntaxe et de modifications de quelques comportements problématiques.
La documentation a bénéficié des efforts portés : elle traite une plus grande partie de l'API, avec plus d'exemples et plus d'explications. Les différents guides ont été rassemblés dans le livre. Le site Rust by Example est désormais maintenu par l'équipe Rust.
Des chiffres !
Projets utilisant Rust
OpenHub tient des statistiques sur l'utilisation de Rust dans les projets qu'il recense, comme pour tout autre langage. On peut ainsi voir que le nombre de personnes qui modifient du code Rust est relativement faible, mais augmente (de 165 projets pour la version 0.12 à 177 dans les projets recensés et 1 025 090 lignes de code). Par ailleurs, le nombre de projets recensés sur GitHub passe de 3262, lors de la sortie de la 0.12, à 4892.
Évènements
De nombreux évènements sont organisés autour de Rust. La rencontre parisienne, régulière, se tient tous les 3è lundis du mois dans les locaux de Mozilla.
Des rencontres ont aussi eu lieu à Lisbonne (16 octobre), Milan (11 novembre), San Francisco (6 novembre et 18 décembre), Seattle (13 octobre, 10 novembre, 8 décembre et 12 janvier).
Liens
''This week in Rust''
Si vous voulez suivre le mouvement de tout ce qui se passe à propos de Rust sans avoir à lire le détail des commits, des annonces sur la liste de diffusion, de Reddit ou de Twitter, le blog This Week in Rust fait une synthèse hebdomadaire des nouveautés et actualités autour de Rust :
- n°56 10 novembre 2014
- n°57 17 novembre 2014
- n°58 24 novembre 2014
- n°59 1er décembre 2014
- n°60 8 décembre 2014
- n°61 15 décembre 2014
- n°62 22 décembre 2014
- n°63 29 décembre 2014
- n°64 5 janvier 2015
- n°65 12 janvier 2015
Notes de version
Contrairement aux précédentes versions, le fichier RELEASES.md contient directement toutes les informations détaillées sur cette version.
Conclusion
Les exécutables d'installation sont disponibles pour les systèmes Linux, Windows, Mac OS X et le code source reste disponible sur GitHub. À noter que l'équipe de développement de Rust recommande d'utiliser les compilations quotidiennes (''nightly builds'') afin de profiter de tous les changements qui se produiront pendant la phase alpha.
La première sortie Bêta est prévue pour la semaine du 16 février 2015, elle comprendra une réécriture de la bibliothèque std::io
.
Aller plus loin
- L'annonce de la version 1.0 alpha (258 clics)
# Pas encore vraiment stable
Posté par Uther Lightbringer . Évalué à 10.
Petite erreur sur ce point. Le langage ne devrait plus avoir de changement incompatibles, sauf si un problème manifeste était trouvé. Cependant des évolutions importantes mais rétrocompatibles sont déjà prévues dans le futur.
Par contre pour ce qui est des bibliothèques standard, il est encore prévu pas mal de changements non rétrocompatibles au moins jusqu'à la sortie de la version Beta. Il y a entre autre en ce moment une refonte complète de la partie io dans la "stdlib".
# Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à 6.
comme après la V1 il ne devrait plus y avoir de d'incompatibilité, il y a eu des grands traveaux sur les entiers: int/uint en isize/usize, mais pas seulement!
Avant les entiers étaient des types ´modulo', maintenant en mode non release il y a un trap en cas de débordement (signe ou pas) et en mode release, il y a 2 possibilités: le programme s'arrête, ou contine mais le résultat du calcul a une valeur indéfinie (en général le modulo, mais pas garanti) ce qui est très different du C ou le programme est indéfini.
Personnellement j'adore ces changements..
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par grim7reaper . Évalué à 5.
Ça dépend…
Ce que tu dis c’est défini dans le « standard » de Rust ou c’est seulement un truc proposé par le compilo ?
En C, Selon le standard :
- type signé : comportement indéfini si overflow
- type non-signé: comportement « modulo »
Par contre, avec les compilateurs (GCC et clang au moins), il y a des options pour :
- forcer le comportement « modulo » et complément à deux (
-fwrapv
)- trap en cas d’overflow sur les entiers signés (
-ftrapv
et-fsanitize=signed-integer-overflow
)Donc au final, niveau implémentation le C offre la même chose que Rust sur ce point là.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à 3.
Je parle du standard de Rust,
Et pour ce qui est de gcc, -ftrapv est réputé comme buggé j'ignore le statut actuel mais ça a été le cas pendant longtemps..
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par grim7reaper . Évalué à 2.
Tu as un lien vers ce standard ?
Je me doute bien que c’est plus un standard à la Python qu’un standard comme le C ou Ada, mais ça reste intéressant à voir.
T’as un lien là-dessus ?
En tout cas, dans clang/LLVM ça fonctionne vu que c’est utilisé par Seed7
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par JGO . Évalué à 5.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35412
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à 3.
Je n'ai pas de lien vers un standard Rust et j'ignore si ça existe ou pas, voici la discussion sur le comportement des entiers: http://www.reddit.com/r/rust/comments/2q40k2/a_tale_of_twos_complement/
le renommage int->size a eu lieu ensuite.
Le deuxième résultat de google sur ftrapv:
http://stackoverflow.com/questions/20851061/how-to-make-gcc-ftrapv-work
Bon il ne faut pas confondre spec et implémentation, maintenant comme le comportement de Rust inclue le trap par débordement par défaut (en mode non release), logiquement cela devrait être bien tester..
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par arnaudus . Évalué à 4.
Mouais, l'intérêt de standardiser un comportement indéfini me semble relativement limité (à part pour indiquer au programmeur qu'il ne doit pas faire ça). Du point de vue programmation, le comportement indéfini n'a aucun intérêt (puisqu'on ne peut pas l'exploiter, on doit juste l'éviter), et je dirais que le comportement "modulo" a un intérêt très limité (d'une manière générale, il va être buggogène dans 99% des cas, et dans le 1% restant, tout programmeur normalement constitué va faire un modulo explicite, ne serait-ce que pour des raisons de lisibilité et de portabilité).
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par barmic . Évalué à 3.
Ça permet de donner de la liberté à l'implémentation. Pour ce cas particulier j'en sais rien, mais des fois c'est plus simple/plus performant de faire d'une manière sur une plateforme et d'une autre sur une autre. C'est par exemple ce qu'il y a souvent sur l'ordre de traitement des paramètres d'une méthode (imagine
int i = 0; foo(i++, ++i, i++);
) certains langages définissent clairement comment cela sera traité d'autres n'indiquent rien sur l'ordre permettant d'imaginer un réordonnancement des instructions.Pas nécessairement, dans du code qui va vraiment travailler sur du binaire il n'est pas rare d'utiliser cette propriété sans l'expliciter avec un modulo (mais oui moi aussi je préfère traper une erreur).
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à 4. Dernière modification le 26 janvier 2015 à 10:26.
L'intérêt est que quand ça arrive, ça devient beaucoup plus simple a débugger car en C/C++ comme le compilateur est libre de faire tout ce qu'il veut s'il sait une branche de code contient un comportement indéfini et ça peut être très, très compliqué a débugger..
En Rust, avoir une valeur indéfinie et non pas le comportement du programme indéfini simplifie le debugging au prix d'une faible perte de performance.
Et j'ignore pourquoi tu parles du comportement "modulo" ça c'était avant..
PS: il y a bien sûr des entiers avec le comportement "modulo" en Rust (Wrapped je crois) mais le problème est le comportement des entiers "normaux".
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par arnaudus . Évalué à 1.
En fait, je crois qu'on est complètement d'accord : il me parait tout à fait normal d'avoir une erreur ou une valeur à Inf/Nan que de prendre le modulo.
Je ne comprends toujours pas la logique du "comportement indéfini" : clairement, un comportement indéfini signale une instruction invalide (puisqu'elle peut virtuellement avoir n'importe quel effet). Pourquoi ne pas stopper le programme, plutôt que de le laisser se poursuivre dans un état indéterminé?
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par navaati . Évalué à 5.
Parcque ça nécessite d'ajouter au code une instruction conditionnelle testant le dépassement, ce qui a un coût ?
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par arnaudus . Évalué à 2.
Pas nécessairement, je ne pense pas que prendre le modulo nécessite un test, par exemple. Éventuellement, le standard pourrait définir plusieurs comportements en fonction de l'architecture, ce qui est pas pareil qu'un comportement indéfini.
Ça pourrait être intéressant de voir les différences de performances induites par ce genre de vérifications. Ça pourrait ne pas être énorme. Après, on peut toujours prétendre que le choix du C est stupide pour 90% des applications codées en C, ce qui est certainement vrai. Ça justifierait de ne pas pénaliser les vrais programmes nécessitant d'être près de la machine parce que les gens ne savent pas utiliser des langages de haut niveau pour coder un démineur.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par grim7reaper . Évalué à 3.
Il y a ce papier de John Regehr, section III D.
Avec la citation de mise en garde:
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par LupusMic (site web personnel, Mastodon) . Évalué à 2.
Mais peut-être qu'un circuit électronique faisant le test peut avoir une différence de coût ou de performance. Le C prend en compte que le langage sera utilisé sur des plate-formes inconnues au moment de son élaboration, et laisse des comportements indéfinis ou des comportements définis par l'implémentation pour permettre d'exploiter au mieux le matériel.
C'est tout à fait illusoire, et non-souhaitable. Quand on voit déjà le temps de gestation d'une nouvelle norme, rajouter cette contraire est au mieux stupide. Les comportements indéfinis ou laissé au bon-vouloir de l'implémentation permettent au C d'être portable sur n'importe quelle plate-forme.
Si c'était vrai, depuis 40 ans que le C existe, je crois que les mainteneurs du standard aurait fait quelque chose.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par pulkomandy (site web personnel, Mastodon) . Évalué à 10.
Le but du C est d'etre proche du matériel. Et toutes les architectures ne font pas la meme chose en cas d'overflow. ça peut faire un modulo, ou bien ça peut déclencher une exception matérielle. Dans le deuxième cas, tout le programme s'arrete (sauf si on intercepte le signal, etc). Donc: comportement indéfini pour tout le programe dans la norme C. Dans le cas contraire, soit certaines machines devraient intercepter le signal et faire le calcul du modulo, soit les autres devraient intercepter les overflows et lever une "exception" (ah mais ça n'existe pas en C ça).
Il y a pour cela plein de langages de plus haut niveau tout à fait appropriés et que le C n'essaie pas de remplacer. Avec des solutions différentes selon les cas: une machine virtuelle connue et maitrisée pour Java (avec un comportement bien défini), un système d'exception qui permet d'intercepter le problème en Ada, etc.
Sur les machines ou l'overflow d'un entier déclenche une erreur matérielle, Rust va devoir l'intercepter et reprendre l'exécution du programme. C n'a pas besoin de le faire. D'ou une simplification du runtime pour le C quelle que soit l'architecture cible.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par gnx . Évalué à 0.
Je n'arrive toujours pas à comprendre le cheminement intellectuel qui aboutit à nommer un entier quelconque, un entier par défaut, un entier au format naturel de la plateforme destiné à tous les usages, « taille ». J'avoue que ça me dépasse (je fais un overflow).
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 2.
u64 n'est pas l'entier de taille naturel utilisé par la plupart des langages en 64bits. Par exemple un int est 32 bits en C sur 64bits. C'est bien l'idée. uint n'a pas pour vocation à être un entier quelconque et par défaut. u32 est par défaut. Il faut voir u32 comme int et u64 comme long, et uint comme size_t. Usize a vocation à representer n'importe quelle intervalle addressable par la plateforme courante. Son utilité est donc par exemple pour indexer un tableau, ou donner la taille d'une collection en mémoire en garrantissant qu'il n'y aura pas d'overflow. Il est donc naturel de l'appeler "taille". Exactement comme size_t.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Lutin . Évalué à 2.
J'ai toujours appris que la taille naturelle d'un int est égale à la taille du bus de donnée d'un CPU, je pensais que c'était dans la norme.
De toute façon on spécifie toujours la taille des int, stocker du 16bits dans un conteneur 8bits arrive plus souvent qu'on ne le croit.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Antoine . Évalué à 3.
"Bus de données", ça ne veut plus dire grand'chose de nos jours. Il y a des tas de bus dans un processeur et autour, avec des largeurs différentes. Déjà, le Pentium (il y a 20 ans !) adressait la mémoire par paquets de 64 bits alors que c'était un processeur 32 bits.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Disons que int est mappé sur la taille la plus pratique. Le C propose 3 type d'archi 16 32 et 64 bits. Le 16 bit est le minimum même sur µC avec registre 8 bits (qui sont souvent mixte 8/16 bits en fait). 32 bit est la norme pour ceux à registre 32 bits. Ce qui ont des registres 64 bits, utilise int en 32 bits, ce qui est incompatible avec les pointeurs 64 bits.
C'est pour ça qu'il y a 3 "sortes" de C. D'ailleurs, il n'est pas possible de faire un code sans ifdef qui reste compatible avec les 3 tailles de registres.
"La première sécurité est la liberté"
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par gnx . Évalué à 2.
Il y a 2 sujets.
Le premier (le défaut).
Quand j'ai écrit « par défaut », ce n'était pas dans le sens où un entier sans type explicite va prendre ce type là, mais dans le sens où c'est le type qu'on utilise quand on n'a pas de besoin spécial. Je n'aurais probablement pas dû utiliser ce mot là, mais il me semble que ceux qui le précédaient et le suivaient précisaient le sens.
Donc il n'y a pas de type de base (passe-partout) adapté à la plateforme et le type automatique est 32 bits ? J'avais cru comprendre que ce langage voulait (entre autres) cibler le bas-niveau. Ça ne me paraît pas génial pour des µC 8 / 16 bits (ou des µC et SoC 32 bits mais avec un bus de 16 bits) ; il faudrait si c'est comme ça faire à coup d'#ifdef pour chaque plateforme pour se définir son type de base adapté. Ou bien ce genre de plateformes n'est de toutes façons pas visé ?
Le second (le choix du nom du type).
En C, utiliser (s)size_t pour autre chose que des tailles (sizeof, *alloc, write, read etc.) me donne déjà des boutons (pour un indice de tableau, brrr…). Et là c'est exactement pareil. Pourquoi donner un type nommé « taille » à un index (ou à un offset ou à un intervalle ou à n'importe quoi qu'on va ajouter à une base, qui est un entier, mais qui représente tout sauf une taille). Mais bon, puisqu'à vous, ça vous semble naturel, ce n'est pas trop la peine d'épiloguer sur le sujet une fois nos avis exprimés, on ne sera pas d'accord.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Antoine . Évalué à 3.
Non, cela dépend de l'ABI, qui dépend elle-même à la fois de l'architecture et de la plateforme logicielle. Ainsi, sous x86 et x86-64 un int est toujours 32 bits. Par contre, un long sous x86-64 est 64 bits sous Linux mais 32 bits sous Windows. Et ainsi de suite…
Il peut donc très bien y avoir des plateformes où un int est 16 bits. Par contre, il ne faut pas trop espérer y faire tourner des programmes existants sans un effort de portage ;-)
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 3. Dernière modification le 31 janvier 2015 à 16:05.
Sur le choix d'un type non signé pour indexer les tableaux :
Je crois qu'il est urgent de faire admettre à la communauté C++ que ce choix est une énorme ânerie. Ce n'est d'ailleurs pas gagné d'avance. Je me permet de rappeler quelques inconvénients d'utiliser un type non signé pour indexer les tableaux.
1) for(std::size_t k = v.size() - 1; k >=0; --k) fait une boucle infinie, ce qui est assez surprenant pour un "débutant"
2) for(std::size_t k = 0; k < v.size() - 1; ++k) est assez drôle lorsque v.size() == 0
3) Pour les types non signés, k + 1 < size() + 1 n'est pas équivalent à k < size(). En effet, si k = 0 et size() contient la valeur maximale du type std::size_t, k < size() est vrai alors que k + 1 < size() + 1 est faux (En effet size() + 1 == 0!). Un compilateur ne peut donc pas optimiser cette expression avec des types non signés alors qu'il le peut avec des types signés car l'overflow de ces types n'a pas à renvoyer un résultat modulo 232 (ou 264).
Inutile de poster toutes les raisons absurdes qu'on entend souvent pour justifier l'utilisation des types non signés. Si vous n'êtes pas convaincu par mon explication, regardez cette vidéo : http://www.youtube.com/watch?v=Puio5dly9N8. Plus particulièrement aux instants 42:38 et 1:02:50 . Vous verrez que Bjarne Stroustrup, Herb Sutter et Chandler Carruth sont aussi d'accord pour dire que c'est une ânerie.
Au passage, comme je fais du calcul scientifique donc grand utilisateurs d'arrays, j'ai réécrit mes propres std::vector et std::array pour pouvoir travailler avec des entiers signés et pour avoir des "custom allocators" qui ne changent pas le type du conteneur, à la manière de ce que font les gens de Bloomberg.
Gnx, on est donc plutôt en bonne compagnie :-).
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 0.
Je crois que le vrai problème dans ton histoire c'est que tu confonds indexer et iterer. Quand tu en arrives à utiliser un iterateur manuel pour itérer un tableau il y a un soucis.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 1. Dernière modification le 02 février 2015 à 11:33.
Enj0lras: Je ne vais pas m'attarder sur le ton condescendant de ton message. Revenons plutôt au sujet.
Si je comprends bien ton message, tu ne comprends pas pourquoi j'utilise des entiers pour traverser un tableau alors que le C++ permet bien d'autres manières à savoir :
ou encore plus simplement en C++11 :
La raison est la suivante. J'écris des programmes où la performance est primordiale ce qui passe entre autre par une utilisation optimale du cache des processeurs. Prenons l'exemple d'un simulateur d'écoulement de fluide où chaque cellule (imagine qu'il y a souvent 100 000 000 cellules) à des propriétés de pression, température, densité, composition, etc. On peut facilement avoir une vingtaine de paramètres. On peut utiliser une structure de donnée qui consiste à déclarer :
et utiliser un std::vector< State > v(100 000 000). Avec une telle structure de donnée, on pourra effectivement utiliser les itérateurs. Seulement, il arrive souvent qu'on doive traverser le tableau et ne récupérer que des informations liées à la pression et la densité par exemple. Une ligne de cache fait 64 octets sur un x86-64 alors qu'un double ne fait que 8 octets. Si pressure et density ne sont pas dans la même ligne de cache, le processeur va devoir à chaque fois charger des lignes de cache pour n'utiliser qu'un huitième de l'information disponible. Le perte de performance est donc énorme.
Une autre méthode consiste à déclarer
où tous ces vecteurs ont la même longueur n, à savoir le nombre de cellules. Si maintenant, on veut faire une boucle pour n'utiliser que la pression et la density, on fait
L'avantage est que tout ce qui est chargé dans le cache est utilisé. Si le programme est limité par la bande passante, il peut dans ce cas être 8 fois plus rapide, ce qui est non négligeable. Maintenant, avec une telle structure de donnée, je ne vois pas comment on fait avec des itérateurs. Les index restent donc très utiles pour beaucoup de personnes.
Si tu souhaites te renseigner, cette méthode qui consiste à utiliser des "struct of arrays" au lieu d'"arrays of structs" est une des bases de ce qu'on appelle le Data Oriented Design. Mike Acton qui s'occupe de jeux vidéos est une des personnes qui passe le plus de temps à expliquer cela. Voici une de ses conférences : https://www.youtube.com/watch?v=rX0ItVEVjHc .
Tout cela pour dire, que non, je souffre pas d'un problème d'incompétence sur les itérateurs; j'ai seulement des besoins de performance et des solutions où les itérateurs ne peuvent pas être utilisés. Si tu as des arguments solides pour dire que l'utilisation d'entiers non signés pour indexer les tableaux est une bonne idée, prends ta plume et va écrire à Bjarne Stroustrup et Herb Sutter. Au passage, tu peux aussi écrire à Scott Meyer qui mettait déjà en garde la communauté C++ en 1995 sur les risques des entiers non signés : http://www.aristeia.com/Papers/C++ReportColumns/sep95.pdf . Il n'a malheureusement pas été entendu.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 4.
Pour ce qui est de messages condescendants, je trouve que tu es assez expert. Tu parles d'optimisation qui devrait avoir un impact sur l'API, je trouve que c'est une assez mauvaise idée. Ce que j'essaye de dire, c'est que le problème que tu soulèves est inapplicable à rust, parce que 'l'index' du tableau n'est pas censé (et ne devrait jamais) être utilisé pour itérer sur le tableau lui même.
Je ne vois pas en quoi ton exemple (qui est d'ailleurs relativement courant) implique l'impossibilité d'utiliser un iterateur. Un iterateur est implémenté (et optimisé) exactement comme ta boucle en utilisant un pointeur au lieu d'un entier, le compilateur étant capable d'optimiser correctement l'arithémtique sur les pointeurs.
Rust fournit l'itérateur Zip pour gérer exactement ce cas : http://doc.rust-lang.org/std/iter/struct.Zip.html . Je ne vois vraiment pas, cache ou pas cache, en quoi un itérateur serait moins performant qu'une boucle avec un entier.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 2. Dernière modification le 02 février 2015 à 01:35.
PS : je voudrais ajouter qu'en outre, utiliser un entier est (peut être, je ne suis pas assez expert pour savoir ce que llvm est capable ou n'est pas capable d'optimiser dans ce cas) moins performant, pour une raison simple. Rust ajoute du bound check au runtime, pour vérifier que l'opérateur d'indexation array[i] n'indexe pas une zone mémoire non initialisée. Si llvm n'est pas suffisament intelligent, il est probable que ton code d'exemple utilise deux branches : une lors de la boucle (ou de l'iterateur) pour vérifier que l'appel à .next() n'a pas dépassé la fin du tableau. Et une nouvelle quand tu vas appeler l'indexation [] pour vérifier à nouveau ce prédicat. Encore une fois, llvm est peut être en mesure d'optimiser ça mais je n'y mettrais pas ma main à couper. Les optimisations valides en C++ ne le sont pas forcément en rust.
Par contre l'itérateur Zip est peut être un peu moins peformant parce qu'il n'est pas au courant que les deux vecteurs ont exactement la même taille. Cela dit, il est probablement possible d'exprimer cela avec un peu d'imagination.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 1.
Tout d'abord, je tiens à préciser que je parle du C++ et non de Rust que je ne connais pas.
La fait de passer d'un "array of struct" à un "struct of array" change effectivement l'API. Mais ces optimisations sont bien trop importantes pour ne pas être faites dans les programme que j'écris.
Concernant le bound-checking, il n'est jamais activé en mode "Release" car il a trop d'impact sur la performance en C++. Le Rust est une autre histoire car les vecteurs sont intégrés dans le langage et non dans une bibliothèque.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 4.
Je ne dis pas que ce genre d'optimisation n'est pas important, juste qu'en arriver à dire qu'il faut pour les appliquer itérer sur des collections avec des entiers est une mauvaise idée. Utiliser des entiers non signés pour itérer sur une collection est une très mauvaise idée. D'un autre côté, utiliser un entier signé pour indexer un tableau est aussi une mauvaise idée, puisque du coup le bound check devient plus couteux : il faut vérifier les deux bounds !
Pour ce qui est d'un usage performant des itérateurs dans ce cas, en y réfléchissant, je ne vois aucun moyen simple pour éviter N comparaisons (au lieu d'une avec une boucle) pour vérifier qu'aucun itérateur n'est arrivé au bout du vecteur. En effet il faudrait des types dépendants pour exprimer que les vecteurs ont tous la même longueur. La seule solution que je vois à ce problème serait d'écrire une nouvelle structure de donnée, VecN ou pusher un élément le pusherait dans tout les sous vecteurs. Dans tout les cas, cela soulève des questions intéressantes sur un usage optimisé des itérateurs, mais je maintiens qu'utiliser des entiers pour itérer une collection est une mauvaise idée.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 2.
Pour ce qui est du cout du bound check (en C++) avec des entiers non signés, c'est une opération:
et avec des entiers non signés, c'est aussi une seule opérationk < n
Comme le passage de int à unsigned int est une opération qui n'en n'est pas une pour le processeur, le cout est exactement le même. Il n'y a donc qu'un seul bound à vérifier. Je te promet que l'utilisation des entiers non signés n'a que des inconvénients et aucun avantage par rapport à des entiers signés.static_cast<unsigned int>(k) < static_cast<unsigned int>(n)
Je pense que là où on ne se comprends pas est que tu parles souvent de collection et je parle de tableau. Qu'on traverse une liste chainée ou un tableau avec des itérateurs, on ne voit aucune différence dans le code source. Cela fait plaisir aux adaptes de la programmation générique, mais cela me gêne si on veut avoir une bonne image de la performance de ce qu'on écrit. Traverser une liste chainée est une catastrophe au niveau du cache alors qu'un tableau est la structure de donnée qui est la plus facile à traiter pour pour ce dernier.
Pour les mêmes raisons, l'utilisation d'OpenMP est basée sur l'indexation avec des entiers et ne marchera jamais avec des itérateurs tout simplement car cette abstraction fait qu'on oublie qu'on travaille avec un tableau.
Dans mon domaine (calcule scientifique), les itérateurs ne sont donc jamais utilisés. C'est aussi la raison pour laquelle le Fortran est encore très populaire dans ce domaine : c'est le langage qui a la meilleure implémentation des tableaux.
Sinon, question performance, j'aime beaucoup les conférences de Chandler Carruth qui s'y connait bien car il a travaillé longtemps sur l'optimiseur de LLVM : https://www.youtube.com/watch?v=fHNmRkzxHWs . Son discours se résume en une phrase : "Utilisez au maximum les tableaux".
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 1.
Je sais pas si ça a avoir avec cette discussion, mais :
https://github.com/cgaebel/soa
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à 2.
Ça c'est une réactions aux vidéos de Jonathan Blow sur Jai.
Pas mal, mais dans Jai, tu peux avoir un pointeur sur un objet que tu change de SOA à AOS (ou vice versa) sans modifier le code et je ne crois pas que ça soit le cas ici, je vais essayer d'avoir + d'infos..
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 0.
C'est effectivement l'utilité de ce genre de bibliothèque.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à 3.
Tu réponds trop vite à Enj0lras.
Pour s'assurer qu'un index non-signé est valide pour un accès à un tableau,
c'est une opération: index < longueur.
Pour s'assurer qu'un index signé est valide pour un accès à un tableau,
c'est deux opérations: index < longueur ET index >= 0.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 2. Dernière modification le 03 février 2015 à 13:55.
Non, j'ai pas répondu, parce qu'il a raison, en quelque sorte, cast + une comparaison suffit à garrantir le fait qu'une zone mémoire qui n'est pas initialisée n'est pas lue, ça ouvre seulement la porte à plus de bugs logique (genre, si tu passes -1, ça va faire de la merde, mais pas plus que si tu passes 230 au fond.)
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à 2.
Ah oui, je me suis loupé aussi, mince!
Merci de m'avoir corriger.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 1. Dernière modification le 03 février 2015 à 14:59.
Si k = -1 (int) et n = 2 (int), alors static_cast< unsigned int >(-1) est égal à 232 - 1 et static_cast< unsigned int >(2) est égal à 2. La comparaison renvoie donc bien false comme on le souhaite. Le bound checking se fait donc parfaitement avec des entiers signés en une seule opération. Pour se convaincre que le cout est le même, il suffit de regarder l'assembleur de :
et debool in_range(int k, int n) {
return static_cast<unsigned int>(k) < static_cast<unsigned int>(n);
};
Ce sont exactement les mêmes (testé avec clang++).bool in_range(unsigned int k, unsigned int n) {
return k < n;
};
De toute façon, le problème du bound-checking sur chaque élément n'est pas vraiment une histoire de une où deux comparaisons. Sa présence empêche la vectorisation automatique et bien d'autres optimisations. Il est donc impossible d'avoir un bound-checking en C++ sans perte de performance notable. Le seul moyen pour avoir un bound-checking raisonnable est que les tableaux fassent partie du langage comme en Fortran, C# ou Rust. Il faut ensuite mettre tout cela dans le compilateur ce qui ne doit pas être une mince affaire. Je crois par exemple que l'équivalent C# de
vérifie une fois avant d'entrer dans la boucle que n <= v.size() et ne fait plus aucun bound-cheking ensuite. On peut alors dire que le bound-cheking a un impact négligeable sur la performance. Mais, je ne crois pas que ces idées soient poussées très loin.
Enfin, pour remettre une couche sur les itérateurs, on fait comment une recherche dichotomique dans un tableau trié avec des itérateurs ? ;-)
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à 2.
Ce n'est pas la première fois que je lie ça donc j'imagine que ça doit être vrai, bon je trouve ça plutôt surprenant: la vectorisation 'automatique' c'est plutôt pour des boucles très régulières et dans ces cas là un compilateur intelligent (comme tu en donne un exemple) n'a même pas besoin d'introduire des check..
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 1.
Il n'y a pas de bound-check en C++ dans le langage. Tout est fait dans la bibliothèque standard. Si v est un std::vector, et que la STL est en mode debug, pour chaque accès à v[k], il y a du code qui vérifie la valeur de k et qui selon les implémentations de la STL lance une exception ou stope le programme. Tout ce qu'il voit en mode debug sur une boucle très régulière du type
c'est qu'il ne sait même pas si il va finir la boucle ! Le compilateur ne peut donc plus rien faire. C'est un des gros désavantage du C++ d'avoir mis trop de choses dans la bibliothèque plutôt que dans le langage. Le seul moyen que je vois pour faire cela correctement est d'avoir les tableaux qui font intégralement parti du langage. C'est le cas en Fortran et en C#. Tu sembles dire que ce n'est pas le cas en Rust.for (int k = 0; v < v.size(); ++k)
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 1.
Les tableaux ne font pas (plus) vraiment partie du langage en rust, ils sont implémentés dans la stdlib.
L'implémentation des vecteurs est purement dans la stdlib : http://doc.rust-lang.org/src/collections/vec.rs.html#139-143
Les tableaux sont batards, le type est un type du langage, mais quasiment toutes les fonctionnalités sont dans la stdlib :
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 1.
On utilise la méthode
de la bibliothèque standard sur un tableau.fn binary_search_by(self, f : F) -> Result<usize, usize> where F: FnMut(&<Self as SliceExt>::Item)
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 1.
Et il renvoie quoi ? Des entiers (Result< usize, usize >) ! Ce serait pas des index par hasard ? ;-)
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 1.
Absolument. Mais pas des iterateurs. rechercher un élement = pas un truc sur lequel tu fais une boucle.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par grim7reaper . Évalué à 3.
Avec un random-access iterator ça doit se faire très naturellement (cela dit, la fonction de la bibliothèque standard ne requiert qu’un ForwardIterator).
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à -1. Dernière modification le 03 février 2015 à 18:34.
Une recherche binaire sur une liste chainée (qui a un ForwardIterator) !!! Il est fort le Rust. Ca n'a aucun sens.
http://stackoverflow.com/questions/5281053/how-to-apply-binary-search-olog-n-on-a-sorted-linked-list
Sur le site de Rust, je ne vois que des recherches binaires sur des slices (qui sont des tableaux). Je ne vois d'ailleurs pas ce qu'on pourrait faire d'autre. Si vous faites une immense queue et que tout ce que vous voyez c'est votre voisin de devant, vous êtes incapable de savoir ou est le milieu de la queue en une seule opération !
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 2.
Tu as l'air de penser qu'il n'existe que 2 types de structure de donnée. Quid des arbre ? Des priority queue ou des ring_buffer ?
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par xcomcmdr . Évalué à 2.
Et les dictionnaires, etc.
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 0. Dernière modification le 03 février 2015 à 20:29.
Sans exagérer, les seules structures de donnée que j'utilise sont basées sur des tableaux. Quasiment tout le calcul scientifique se fait avec cela, ce qui explique pourquoi le Fortran est encore très adapté à ces tâches. Il est très rare d'avoir à sortir un algorithme difficile ou une structure de donnée tordue. J'ai même fait un tri bulle une fois sur des tableaux; Comme il y avait 100 000 000 de tableaux de 14 éléments à trier, c'est ce qu'il y a de plus efficace ;-)
Il est évident qu'il y a d'autres domaines où des structures de données complexes sont utiles, les compilateurs par exemple. Seulement, de nombreux programmeurs expérimentés reviennent aux tableaux quand il faut être efficace. Regardez par exemple cette présentation de Chandler Carruth (Responsable du C++ chez Google et développeur de la partie optimisation de LLVM). Je vous résume le talk en une phrase : "Pour la performance, dès que vous le pouvez, utilisez des tableaux". https://www.youtube.com/watch?v=fHNmRkzxHWs
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 3.
Je ne vois pas ou tu tu veux en venir.Evidemment que des tableaux auront un meilleur comportement vis à vis du cache, et que niveau perf, c'est bien, mais je ne vois pas en quoi ça contredit le fait d'avoir une api générique du moment qu'elle n'a pas de cout pour quand tu veux utiiser un tableau. C'est assez pratique pour les gens qui utilisent d'autres structures de données que d'avoir la même api pour tout, ça rend les choses plus simples à mémoriser.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par grim7reaper . Évalué à 2.
Oui, surtout qu’en l’occurrence je parlais de C++…
Et oui, pour le coup tu peux faire une recherche dichotomique sur une liste chaînée (mais il précise bien que tu seras plus performant avec des RandomAccessIterator).
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par Enj0lras . Évalué à 2.
ça fait sens si ta fonction de comparaison est linéairement plus couteuse que parcourir a liste. Par exemple, une liste de chaine très longues. Mais bon à ce niveau autant utiliser un arbre.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par grim7reaper . Évalué à 2.
Ouais, un truc genre HAT-trie.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par InsideLoop . Évalué à 1.
Sur le type pour indexer un tableau:
Au passage, un bon choix de type pour indexer un tableau est std::ptrdiff_t ( http://en.cppreference.com/w/cpp/types/ptrdiff_t ). Sur une machine 64 bits classique c'est un entier signé sur 64 bits.
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à -9.
Ton poste me laisse penser que tu n'as pas bien lu ce qu'on a marqué..
Un exemple, si tu marque "let maVar = 5;" il faut choisir le type entier pour maVar (i32 maintenant), autrement tu peux imposer a l'utilisateur de spécifier toujours la taille du type mais ça devient rapidement lourd..
Toi y en a comprendre?
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par j_m . Évalué à 5.
Soit dis en passant, tu sais que ce genre de phrase signe pour la plupart des gens l'intention d'être désagréable ?
Ca vient faire quoi dans le fil de la discussion ?
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par reno . Évalué à 0.
Et bien c'est un peu agaçant de voire des réponses où l'auteur n'a pas lu le poste..
[^] # Re: Une chose que j'ai oublié d'ajouter
Posté par j_m . Évalué à 8. Dernière modification le 26 janvier 2015 à 22:02.
Ecrire et attirer l'attention des gens sur ce qu'on veut, c'est un art.
Si tu voulais que les gens fassent attention à autre choses qu'à l'injure, ben quelque chose a raté. Il faut réessayer.
# Un langage complexe ?
Posté par Enj0lras . Évalué à 2.
Je ne sais pas quel est le point de vue des autres rustacean, mais je trouve personnellement que rust est le langage qui m'a donné/me donne le plus de mal à apprendre.
Beaucoup plus compliqué que des langages fonctionnels comme ocaml ou que C, et même plus compliqué à comprendre que des langages à types dépendants. Cela dit, je pense que ça en vaut quand même la peine.
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 4.
Tu as des exemples de complexités ?
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par Enj0lras . Évalué à 5.
La grande difficulté vient du système de propriété/emprunt et de la délégation récursive de la mutabilité. Comprendre les règles qu'appplique le système de type est assez hardu au premier abord, d'autant plus qu'il n'y a quasiment aucune documentation qui les explique formellement.
Quand tu codes, il t'arrive souvent de t'ennerver parce que tu as l'impression que le code devrait être valide alors que le compilateur ne l'accepte pas (il a souvent raison parce qu'il applique des règles plus généraes et même si ton code est correct dans ce cas particulier, le compilateur n'est pas à même de le comprendre). Il est aussi souvent assez rageant aussi d'être limité par le fait que la propriété fonctionne par environnement lexical, ce qui t'amène souvent à devoir ré-écrire ton code pour qu'il soit accepté d'une manière que tu trouves moins lisible. (par exemple, sortir le code d'un bloc et le mettre "plus haut" dans l'abre des environnement lexicaux)
Cela dit, quand tu commences à maitriser les règles du typeur, tu peux écrire du code qui type correctement et qui reste élégant. La difficulté est d'en arriver à ce point de maitrise du langage. Maintenant si tu veux des exemples de code il va falloir que j'y réfléchisse un peu :).
[^] # Re: Un langage complexe ?
Posté par reno . Évalué à 4.
Pas étonnant:
-Le C est simple a coder car le compilateur te laisse faire n'importe quoi, à débugger par contre..
-Ocaml et les autres langages fonctionnels ont un GC, ce qui simplifie beaucoup la programmation, mais tu en paye le prix à l'exécution..
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 1.
On pourrait imaginer le GC pilotable. rust permet un peu ça, et permet aussi d'avoir des zones mémoires hors GC.
ocaml pourrait permettre de réutiliser des variables en tant que bloc mémoire inutile. J'ai souvenir d'écriture d'un parseur, qui lisait des milliers de petit fichiers, qui devait à chaque fois réallouer une nouvelle string pour les lire.
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par barmic . Évalué à 7.
Personnellement je ne pense pas que les gc posent vraiment problème. Ils sont tout à fait capables de gérer correctement les choses même avec de fortes charges et pour peu qu'on ne fasse pas n'importe quoi on arrive à des cas où les full gc (ou équivalent) ne se déclenchent presque jamais. Le problème c'est de croire que l'on peut continuer à faire des logiciels aujourd'hui comme on en faisait il y a 25 ans avec un seul gros programme qui fait tout. Les gc sont juste révélateurs de ces cas où l'architecture n'est pas idéale.
Si tu découpe ton programme en plusieurs petits programmes, le boulot du gc devient bien plus simple, ton boulot de développeur aussi, les perf s'améliorent par une meilleure utilisation des CPU,…
Bref si les gc ne sont pas aussi performants que la RAII et qu'ils ne s'appliquent qu'à la gestion de la mémoire1, ils ne représentent un vrai goulot d'étranglement que dans des cas où tu cherche de la très haute performance et dans les cas où l'organisation de ton appli n'est AMHA, pas adaptée.
si tous les programmeurs qui utilisent des gc avaient conscience que le gc d'une part n'empêche pas les fuites mémoire et d'autre part ne gère qu'une partie des problème de gestion des ressources. Ce serait déjà un grand pas. ↩
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Un langage complexe ?
Posté par reno . Évalué à 4.
Ça c'est de l'assertion! Parles en aux développeurs qui font des jeux: 60 images/sec (16ms par image), ça va les intéresser..
Personnellement je travaille sur des générateurs réseaux et l'idée d'avoir un GC qui me rajoute des latences aléatoires, beurk..
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 4.
Au pire dans le temps réel dure, on ne fait pas d'allocation de mémoire du tout (Misra C). Ou on le fait uniquement après le démarrage de l'application, puis on y touche plus (type serveur graphique Arinc 661).
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par pulkomandy (site web personnel, Mastodon) . Évalué à 2.
Ce n'est pas impossible d'avoir un GC dans un système temps réel (ou n'importe quel autre système de gestion dynamique des allocations mémoire). ça complique un peu les choses, il faut avoir un GC exécutable de façon planifiée et avec un temps 'exécution borné, mais dont on est sur qu'il peut libérer au moins autant de mémoire qu'il en a été allouée depuis sa dernière exécution.
ça a été fait par exemple ici avec du Java: http://www.ghs.com/news/20100302_IS2T_java_support.html
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
J'imagine que la démonstration de "ça passe" doit être compliqué.
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par whity . Évalué à 3.
Il y a plein de bouts dans les jeux vidéos qui sont faits dans des langages garbage collectés (c#, python, scripts divers), sur des parties non critiques.
Bien sûr, ça ne concerne généralement pas le moteur graphique quand on veut de la perf à tout prix.
Mes commentaires sont en wtfpl. Une licence sur les commentaires, sérieux ? o_0
[^] # Re: Un langage complexe ?
Posté par barmic . Évalué à 3.
C'est du temps réel, ça fait partie AMHA des domaines où tu as de gros besoins de performance. On voit bien ce gros besoin de performance par l'utilisation de matériel dédié à ce besoin (tous les circuits graphiques quand il ne s'agit pas carrément d'une carte d'extension), par l'utilisation généralisée de framework servant principalement à tenter d'abstraire/industrialisées les bonnes pratiques et les utilisations d'API pensée pour la performance.
Donc oui, pour moi, même s'il ne s'agit pas de temps réel dur, ça rentre complètement dans le cas du gros besoin de performance.
Ceci dit même avec ça bon nombre de jeux sont écris tout ou parti avec des langages à gc.
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Un langage complexe ?
Posté par LupusMic (site web personnel, Mastodon) . Évalué à 1.
Tu as une source qui étaye cet argument ?
Parce que certes, les jeux côté serveur sont souvent écrits en un langage de script. Mais quand on regarde les jeux qui fonctionnent dans des environnements contraints (consoles de jeux), le C++ a une grosse part. Par exemple https://www.youtube.com/watch?v=X1T3IQ4N-3g
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Beaucoup de jeu utilise un énorme truc en C++ mais un langage de script pour le reste. Unity https://fr.wikipedia.org/wiki/Unity_%28moteur_de_jeu%29 utilise mono. D'autres utilisent Lua.
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par barmic . Évalué à 4.
De chiffre non, mais quand on voit le nombre de frameworks comme pygame, Unity, UnrealScript, XNA à l'époque,… je doute que ce soit fait pour l'amour du code non utilisé :-)
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Un langage complexe ?
Posté par LupusMic (site web personnel, Mastodon) . Évalué à 3.
Tu peux citer des jeux commerciaux qui utilisent PyGame ? Pour des point-n-click c'est intéressant, mais je doute qu'on puisse faire un jeu qui exige des ressources (FPS, RTS, etc). D'ailleurs, Python est une erreur pour tout jeu demandant des performances d'affichage et demandant du parallélisme. Et le problème est justement le GC qui a encore un lock global.
Unity est principalement utilisé par des indépendants ou des amateurs. Tout comme XNA.
UnrealScript est en effet un bon exemple.
Bref, le choix de la technologie est évidement dépendant du type de jeu qu'on veut développer. Mais il est évident que le C++ reste le langage de choix pour développer un jeu vidéo sérieusement.
Il serait intéressant de creuser cette page Wikipedia qui n'est pas très étayée : http://en.wikipedia.org/wiki/Game_programming#Programming_languages
[^] # Re: Un langage complexe ?
Posté par Antoine . Évalué à 2.
Mouarf. Un peu comme les pieds nickelés qui contribuent à tous ces logiciels libres que tu utilises ?
Quel est ce sous-entendu ridicule selon lequel un jeu indépendant ne serait pas digne d'être cité en exemple ?
(note que beaucoup de jeux indépendants sont vendus dans le circuit commercial)
Python utilise un comptage de références, donc tu peux très bien désactiver le GC si tu fais gaffe à ne pas laisser traîner de cycles de références. Ce n'est pas idéal mais ça marche (je crois qu'EvE Online fait ça, si j'en crois quelques messages d'un de leurs développeurs).
[^] # Re: Un langage complexe ?
Posté par Moonz . Évalué à 2.
Ça m’intéresse. C’est débugguable ça ? (genre une option pour crasher en cas de cycle au lieu de lancer le GC…)
[^] # Re: Un langage complexe ?
Posté par GuieA_7 (site web personnel) . Évalué à 2.
Ça n'a pas de sens ; dans un système par comptage de référence, un cycle entraîne une fuite mémoire. Et il faut justement un GC pour détecter automatiquement ces cycles (si notre cerveau ne l'a pas fait en lisant le code donc). Donc si tu veux un crash il faut lancer quand même le GC, mais crasher plutôt que libérer la mémoire.
En revanche tu peux:
[^] # Re: Un langage complexe ?
Posté par Moonz . Évalué à 2.
Non, le sens c’est activer le GC en dev/test/debug et qu’il signale comme erreur un cycle, afin de pouvoir complètement le désactiver en prod.
À peu près comme tu décrit dans la deuxième partie de ton message, quoi :)
[^] # Re: Un langage complexe ?
Posté par abriotde (site web personnel, Mastodon) . Évalué à 1.
Les langages 'lent' mais 'simple',c'est a dire avec GC (Python, Java, PHP…) sont destiné au développement rapide de 80% du code non contraint. Il y a des milliers de jeux amusants développés en Java/python. Mais des jeux simples du type de Frozen bubble et tous les autres jeux de tablette/smartphone… Pour le 20% du code restant, (le coeur des jeux de gamer (FPS / simulateur et autres)) il n'y a pour le moment que le C/C++. Rust et Go représentent a mes yeux les seuls tentatives intéressantes d'une alternative plus moderne. L'avenir nous dira s'il apportent un vrai plus.
Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.
[^] # Re: Un langage complexe ?
Posté par xcomcmdr . Évalué à 3.
J'ai pas souvenir que Minecraft soit en C++, ni les jeux XNA (C#/.NET).
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: Un langage complexe ?
Posté par LupusMic (site web personnel, Mastodon) . Évalué à 0.
Et Minecraft est d'une lenteur monstrueuse à cause de ce choix. Quand on compare à Minetest, on se demande comment Mojang peut continuer à vouloir utiliser ce veau.
Précisons que Minecraft était un jeu indépendant, et que donc le choix de la technologie ne répond pas au besoin technique mais au besoin de diminuer le coût de production.
[^] # Re: Un langage complexe ?
Posté par xcomcmdr . Évalué à 0.
Pas chez moi. Pas dans les milliers de vidéos de Minecraft sur youtube, etc…
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: Un langage complexe ?
Posté par LupusMic (site web personnel, Mastodon) . Évalué à -1.
« Chez moi ça marche » n'est pas un argument. Par contre « Chez moi A est lent, et B est rapide », est un argument :p
[^] # Re: Un langage complexe ?
Posté par xcomcmdr . Évalué à 2.
"Chez moi ça ne marche pas" n'est pas non plus un argument.
Et mon argument c'était "ça marche très bien chez moi, et chez des milliers d'autres, et si tu en doutes tu as des milliers de vidéos youtube pour te le prouver à portée de souris".
"Quand certains râlent contre systemd, d'autres s'attaquent aux vrais problèmes." (merci Sinma !)
[^] # Re: Un langage complexe ?
Posté par Antoine . Évalué à 7.
En effet, ce naze de Mojang a fait un jeu avec un langage et un environnement de développement qui lui ont permis de maximiser la productivité du développement, et de satisfaire des millions de joueurs. Il n'a manifestement rien compris et aurait dû suivre les conseils de LupusMic< qui démontre avec brio que seul le C++ permet de développer sérieusement des jeux™.
(un peu comme ces zozos de Facebook qui ont construit un empire sur du PHP, alors qu'il aurait fallu écrire des CGI en C ou en Ada)
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 7.
Oui enfin les zozo de facebook ont aussi écrit un nouveau langage 100% compatible php pour corriger les bugs. (the hack langage https://linuxfr.org/news/the-hack-language-php-avec-un-peu-de-typage-statique http://hacklang.org/ )
Cette vidéo sur le pourquoi, ils l'ont fait est super intéressante :
http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Hack
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par djano . Évalué à 3.
Je crois que tu as mal interprété le propos d'Antoine qui se voulait ironique :)
En tout cas merci pour le lien sur le talk de Julien Verlaguet, c'est en effet super intéressant!
Ils ont vraiment peur de rien chez Facebook! Convertir plus de 10 millions de lignes de code de PHP vers Hack, il fallait vraiment oser! En plus leur approche aussi automatique que possible, c'est vraiment hallucinamment bien pense. Maintenant que j'y pense, ils automatisent absolument tout ce qu'ils peuvent. Voir par exemple les notifications automatiques sur les projets Github de Facebook: vous n'avez pas signe le contributor agreement, etc.
Vraiment, cette boite c'est une éclatante réussite de l’ingénierie logicielle, voire de l’ingénierie tout court puisqu'ils font plus que du logiciel maintenant.
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Je sais mais il voulait sans doute dire que malgré que PHP est un outil de merde, facebook a réussi. Sauf qu'à l'époque, il n'avait trop de choix et qu'ils ont changer PHP pour correspondre à leur besoin (typage progressif, jit,…).
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par devnewton 🍺 (site web personnel) . Évalué à 3.
Un GC peut être parfois être plus performant pour un jeu que du RAII qui va imposer des désallocations immédiates alors que ça peut attendre la fin du niveau.
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Un langage complexe ?
Posté par navaati . Évalué à 4.
Le RAII te laisse le choix.
Si tu veux attendre la fin du niveau pour exécuter des destructeurs couteux, tu peux transférer l'ownership des variables à ton objet représentant le niveau, dans un tableau « poubelle », par exemple.
[^] # Re: Un langage complexe ?
Posté par devnewton 🍺 (site web personnel) . Évalué à 10.
Idem pour le GC: si tu veux éviter des destructions coûteuses, il te suffit de garder des références dans un tableau poubelle ou plus simplement faire du pooling.
GC ou pas GC, la gestion de la mémoire et des ressources demande de l'attention.
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Dans le cas auquel je pense, c'est vraiment pour de l'optimisation, je suis bien d'accord. Le fait de faire plusieurs programme aurait ralentit le tout. Je parle de lire 10 000 fichiers en quelques secondes.
Sans piloter le GC, il pourrait être utile d'avoir un moyen de créer des données totalement hors du contrôle du GC. Cela permet d'éviter des scans inutiles. Voir de se passer complètement du GC dans certain cas, par exemple pour les données qui vont rester en vie, durant toute la vie du programme.
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par barmic . Évalué à 3.
Sincèrement la lecture de 10 000 fichiers c'est plus les accès disques qui vont te poser problème que l'allocation mémoire. Lancer les lectures de manière asynchrone va probablement te permettre de passer un gap très important. Si ensuite tu as un problème vraiment lors de l'allocation, le fait d'utiliser des thrads (qui peuvent par exemple regrouper les lectures par chunk de 100 fichiers va te permettre d'avoir de simplifier le travail du gc, toutes les allocations annexes seront libérées par la destruction du thread).
Les gc générationnels font déjà se boulot avec une granularité plus fine et de manière plus systématique que ce que tu ferra. Si on prend le cas de la JVM, si vraiment tu as des contraintes fortes qui ne sont pas correctement gérées par défaut tu peux tuner finement la JVM pour gérer par exemple les tailles et les durées des générations.
Pour le cas que je connais le mieux. Le problème principal que je vois aujourd'hui (et qui ne sera jamais corrigé) c'est le coût de l'allocation d'un objet. Les sécurités et autre artifices qui entrent en jeux lors de la création d'un objet peut poser un vrai problème (et ne sont pas forcément facile à prendre en compte (mal grès l'utilisation de pool d'objet).
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Pour mon cas, non. En bidouillant le GC d'OCaml, j'avais des perf en plus (10 % de mémoire), en multipliant la conso mémoire par 10 (en gros, le gc se déclenche beaucoup moins ouvent).
Dans le cas de lecture sur le même disque, je ne vois pas pourquoi. Je n'ai pas fait le test, mais je persuadé que tu va juste augmenter le nombre de "seek" et ralentir le tout. Cela se voit bien entre plein de copie en parallèle ou une liste de copie.
Surtout si ta mémoire est read only comme en Ocaml (le parsing se fait uniquement sur les string, sinon, il faudrait tout recoder avec "buffer"). Mais si tu as une génération jamais parcouru par le GC, c'est plus rapide non ?
Dans Ocaml, c'est un déplacement d'un pointeur de pile. Dans le cas de mémoire à faible durée de vie, c'est ultra rapide. C'est ensuite, que cela se complique.
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par barmic . Évalué à 3.
Pas forcément. Faire 10 000 lectures asynchrone ça ne veut pas dire faire 10 000 lectures en parallèle. J'ai pas fais de tests, mais si tu as une API qui utilise correctement celles du noyau, tu dois plus y gagner parce que c'est lui qui sait comment les données sont organiser et qui va répondre au mieux aux demandes.
Oui, mais le gain n'est pas forcément si important que ça et il peut être plus faible que d'avoir des objets qui sont éternels qui sont perpétuellement vérifiés et que tu n'a pas pensé à rendre éternels. Le parcourt de la génération la plus vielle du gc peut être vraiment rare (par exemple elle se déclenchera quand tu aura vraiment mis de la pression sur ton allocation mémoire).
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Un langage complexe ?
Posté par Nicolas Boulay (site web personnel) . Évalué à 2.
Non justement. Linux ne cherche pas à optimiser la bande passante global, ou le temps de fin global. Il essaye d'être juste ("fair") entre chaque flux IO. Il va donc faire un peu de tout, pour satisfaire tout le monde. Il va garantir une latence minimum pour tous. Or, on se fout qu'un des job soient très en retard. Sur un HD, on peut augmenter la bande passante réelle avec des "bandes" jusqu'à ~15 Mo. Plus l'accès est linéaire, plus la copie/lecture est rapide.
C'est justement de ce cas pathologique dont on parle : plein d'allocation suffisamment grosse pour aller dans la "zone vieille" mais à collecter ensuite. Je n'ai pas testé d'augmenter franchement la zone jeune, c'est peut être une autre solution (256Ko de mémoire).
"La première sécurité est la liberté"
[^] # Re: Un langage complexe ?
Posté par djano . Évalué à 3.
En java il suffit de faire du off-heap: toutes ces données seront hors d'atteinte du CC. C'est beaucoup utilisé pour faire du trading haute fréquence pour réduire la latence ou dans les bases de données pour faire des systèmes de cache, ou même dans NIO pour transférer des données en zéro copy.
Je ne sais pas si quelque chose d'aussi facile existe dans les autres langages à GC.
[^] # Re: Un langage complexe ?
Posté par whity . Évalué à 1.
Deux problèmes (vécus) des GCs :
- la latence : l’exécution du GC freeze le programme, dans certains contextes ce n’est pas acceptable
- l’occupation mémoire et la cohabitation avec du code non garbage collecté. Certains GC ont une fâcheuse tendance à ne libérer la mémoire que quand il n’y en a plus, ce qui pose problème dans le cas d’un environnement hybride (typiquement, asp.net avec appel de code non managé) --> si le malloc qui échoue est dans le code managé, le GC se lance, s’il est dans le code non-managé, le GC ne se lance pas, et le code non managé n’aura jamais accès à la mémoire qui lui manque. Après, ce problème pourrait se résoudre par l’utilisation de process séparés, comme tu le préconises, mais cela a un coût. Dans un contexte serveur, le coût d’exécution, c’est de l’argent.
Mes commentaires sont en wtfpl. Une licence sur les commentaires, sérieux ? o_0
[^] # Re: Un langage complexe ?
Posté par barmic . Évalué à 3.
Comme je disais plus haut ce n'est pas nécessairement un processus système et il faut voir de quoi on parle adopter un modèle réactif ou d'un système d'acteur, peut faire gagner beaucoup : http://blog.octo.com/jusquou-peut-aller-un-simple-ordinateur-de-bureau-avec-une-application-web-java-reactive/ (le bench n'est peut être pas représentatif, mais la variation sur un même exemple reste inintéressante).
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Un langage complexe ?
Posté par ckyl . Évalué à 6.
Si. Mais la plupart des besoins sont suffisamment triviaux et affreusement architecturé pour que ça ne soit pas le goulot d'étranglement
Tu n'as pas besoin d'aller au full gc pour que ça pose problème. C'est une vision triviale du problème. Les problèmes sont nombreux et variés que ce soit sur les générations à vie courte ou les objets a vie longue.
Grosso modo il n'y a actuellement aucune implémentation de GC qui arrive à:
- Exploiter correctement le volume de RAM disponible actuellement (grosso modo pour rester dans l'acceptable on plafonne à la dizaine de Go alors que les serveurs ont des centaines de Go de RAM)
- Exploiter la bande passante de la mémoire. Grosso modo pour garder des latences correctes on doit se limiter à 10% de ce qu'est capable un serveur.
La seule exception est Zing d'Azul.
Alors on peut s'en sortir en bricolant mais les GC actuellement n'arrivent pas a suivre le matériel. Si ça t’intéresse, les talks de Gil Tene sont un bon point d'entrée. Après tu peux aller traîner avec les gens qui font d'HFT et leurs potes. Une partie sait à peut prêt de quoi ils parlent.
[^] # Re: Un langage complexe ?
Posté par barmic . Évalué à 5.
C'est très rare les programmes qui ont ce genre de besoin ou du moins si ce n'est pas rare c'est hyper minoritaire. C'est comme si tu me disait qu'avec les langages actuels c'est compliqué d'utiliser efficacement une CPU de 10GHz. Aujourd'hui ce genre d'énorme serveur, on s'en sert rarement pour ne pas dire presque jamais pour lancer une appli qui va consommer toutes les ressources. C'est même pas une question de langage. Pour gérer des coûts modérés, avoir un peu de tolérances aux pannes (même logiciel), on préfère découper les problématiques en de plus petits bouts qui vont soient s'articuler les uns par rapport aux autres soient pour faire de la monté en charge horizontale.
Je dis pas que ça n'existe pas (tu peux avoir envie de traiter en une fois l'ensemble des clichés que ton télescope t'envoie par exemple), mais c'est des cas aux limites, ceux que l'on a pas su découper (par exemple parce que ça n'est pas possible). Partout où c'est possible, on découpe, on fait du sharding. Des exemples réels tu en a pleins je ne pense pas avoir besoin de t'en citer des applications C/C++ ou autre langages réputés pour leur performance où on va s'atteler à découper parce que :
Sérieusement je ne l'invente pas tout ça…
Ça m'intéresse tu aurais un pointeur ?
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
[^] # Re: Un langage complexe ?
Posté par spider-mario . Évalué à 8.
0x7fffedaf087c
[^] # Re: Un langage complexe ?
Posté par GuieA_7 (site web personnel) . Évalué à 2.
Je pense en effet que Rust est assez "élitiste" et la courbe d'apprentissage un peu rude ; j'ai d'ailleurs un peu peur qu'à cause de ça Rust reste assez marginal à l'instar de OCaml ou Haskell.
Un article assez intéressant qui résume assez bien la situation :
http://arthurtw.github.io/2015/01/12/quick-comparison-nim-vs-rust
Bon en l’occurrence il est très probable que Nim reste lui aussi marginal, mais peu importe : Rust est sûrement le langage dans lequel on aimerait avoir codé un gros projet quand sa taille devient un problème, mais ne sera pas peut-être pas être assez "fun" pour débuter ledit projet, quand on ne sait pas encore qu'il va être gros :)
Bon après j'espère me tromper, et l'arrivée de bons outils (aide au refactoring automatisé, autocomplétion, voire même IDE) pourrait bien changer un peu la donne.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.