Zeph (./5015) :C'est exactement ça.
Autant je te rejoins sur le fait que cette transition était infernale et sans fin, autant je ne sais pas s'il y avait une façon de mieux gérer des breaking changes aussi importants que ceux qu'ils avaient à passer pour corriger plein de mauvais choix faits dans la version 2.
Uther (./5016) :Mais il y a eu plein de systèmes pour faciliter la transition, soit en transformant automatiquement ton code Python 2 en Python 3 (outil 2to3) ou le contraire (3to2). Tu pouvais également faire du code compatible Python2 et Python3 simultanément (avec import __futures__ qui ne faisait rien en Python 3 mais patchait en Python2).
Je ne dis pas que la transition n'était pas nécessaire mais je suis convaincu qu'elle aurait pu être mieux organisée pour éviter de couper en deux l’écosystème pendant si longtemps.
Je ne connais pas assez Python en détail pour être sur, mais il y avait probablement moyen de s'en sortir avec des déprécations combinées à un système similaire aux édition de Rust (support de différentes version de la syntaxes par le même compilateur).
Et si ce n'était techniquement pas possible de faire une transition plus naturelle, il aurait au moins fallu forcer d'avantage pour qu'elle aille beaucoup plus vite.C'est dangereux de forcer une communauté qui ne te doit rien. De plus, en pratique, à part quelques bibliothèques (surtout liées au réseau, qui manipulent souvent texte et chaînes binaires), la transition a été lente mais pas tant que ça. Ça fait très longtemps (au moins 8-9 ans) que je n'utilise plus que du Python 3.
Lionel Debroux (./5011) :Merci pour l'info. Je comprends mais je suis quand-même étonné que le HT puisse être moins performant que sans, il faut des cas où les composants partagés comme l'ALU et le cache local (je crois) soient starvés constamment pour que ça se passe, et même dans ce cas ça ne devrait pas augmenter en chaleur (on perd juste l'overhead du multithread). Mais il doit y avoir quelque chose d'autre avec l'architecture Core, parce que deux "threads" consomment en effet assez proche de deux cores distincts pour des gains largement inférieurs, ce qui n'a pas beaucoup de sens pour moi. Mon PC ne tape pas dans la limite de TDP donc je ne peux pas tester, mais il se pourrait qu'un scheduleur mettant par erreur quelque chose sur un deuxième thread puisse faire consommer plus que s'il l'avait mis sur un core non utilisé, rapporté au bénéfice de performance. Mais je crois que Windows ne fait pas ça, il remplit d'abord tous les cores avant de balancer sur les threads. L'exception, c'est pour la performance single core, mais là aussi c'est un "bug" d'Intel, qui fait que si tu bouges souvent un seul thread d'un core à l'autre comme Windows le fait, le processeur va limiter le turboboost, pensant que plusieurs cores sont utilisés (et la fréquence maximale n'est atteignable qu'avec un seul core à la fois). À l'époque j'avais désactivé le HT pour augmenter un petit peu la performance single core, au prix d'environ 30% en multicore. J'imagine qu'il peut y avoir pas mal de problèmes de ce type avec le big.LITTLE, en pire.
L'implémentation de HT s'est améliorée depuis les débuts où il avait été montré que des workloads comme MySQL détestaient l'hyperthreading, avec des pertes de performance significatives. Il reste cependant qu'en l'absence d'informations d'affinité, si le scheduler trouve malin de mettre deux threads qui utilisent les mêmes blocs du processeur sur les 2 hyperthreads du même coeur, plutôt que sur 2 coeurs séparés du même socket, la performance peut être inférieure, et surtout, non répétable.
Sur certaines micro-architectures, la performance inférieure peut aussi être remarquée quand on utilise tous les threads du CPU: la performance de memtest86+ (scheduler statique trivial) avec tous les threads est inférieure à la performance avec 1 seul thread par coeur, malgré une consommation électrique et un dégagement de chaleur habituellement supérieurs. `rep stosl / rep stosq`, ou de courtes boucles similaires, ne s'exécutent pas toujours (voire pas souvent ?) efficacement en parallèle sur 2 hyperthreads du même coeur. La pénalité de l'utilisation du SMT est certes inférieure à celle qu'on rencontre sur certaines machines quand on ne tient pas compte du NUMA (j'ai vu un facteur 15-20 sur une machine Ivy Bridge EP quad socket !), mais elle existe.
Je pense que sur certains workloads, pour avoir des benchmarks fiables, il est encore plus simple de désactiver le SMT que de programmer d'une façon ou d'une autre l'affinité de manière à éviter le SMT.
Et côté vulnérabilités des processeurs, désactiver SMT fait partie des mitigations de L1TF ("Foreshadow-NG"), MSBDS ("Fallout"), MFBDS ("Zombieload"), MLPDS et MDSUM ("RIDL"). Un certain nombre de mes machines tournent sans HT depuis 2018.
flanker (./5017) :Les outils d'aide à la migration c'est vraiment indispensable, mais ça ne résout qu'une partie du problème. Le vrai soucis c'est la cassure nette dans l'écosystème, ce que la majorité des autre langages a réussi à éviter. Le code compatible à la fois Python 2 et 3, si ça peut paraitre une bonne idée a première vue, ça contribue aussi a rendre la transition floue.
Mais il y a eu plein de systèmes pour faciliter la transition, soit en transformant automatiquement ton code Python 2 en Python 3 (outil 2to3) ou le contraire (3to2). Tu pouvais également faire du code compatible Python2 et Python3 simultanément (avec import __futures__ qui ne faisait rien en Python 3 mais patchait en Python2).
flanker (./5017) :C'est vrai que c'est pas forcément un bon plan de forcer une communauté, mais entre mettre le couteau sous la gorge pour migrer immédiatement et supporter un double écosystème pendant plus de 11 ans, il y a un juste milieu. Je pense qu'un calendrier de transition sur 3 ans aurait pu passer. Le fait d'avoir une limite clairement définie dès le départ aurait insité la communauté a faire rapidement la transition.
C'est dangereux de forcer une communauté qui ne te doit rien. De plus, en pratique, à part quelques bibliothèques (surtout liées au réseau, qui manipulent souvent texte et chaînes binaires), la transition a été lente mais pas tant que ça. Ça fait très longtemps (au moins 8-9 ans) que je n'utilise plus que du Python 3.
Uther (./5019) :J'avoue que je ne vois pas du tout où veux en venir
Les outils d'aide à la migration c'est vraiment indispensable, mais ça ne résout qu'une partie du problème. Le vrai soucis c'est la cassure nette dans l'écosystème, ce que la majorité des autre langages a réussi à éviter. Le code compatible à la fois Python 2 et 3, si ça peut paraitre une bonne idée a première vue, ça contribue aussi a rendre la transition floue.
Pour prendre l'exemple de Rust que j'ai bien suivi, je trouve qu'ils ont fait un choix plutôt malin. Le même compilateur peut traiter des fichiers Rust en utilisant au choix la syntaxe de l'édition 2015, 2018 ou 2022 et les lier entre eux de manière totalement transparente. Ils ont aussi fait des outils pour faciliter la migration vers les nouvelles éditions et les projets crées par cargo (l'outil standard de build et gestion des dépendances) utilisent par défaut la dernière édition.
Utiliser la dernière édition est on ne peut plus naturel, et dépendre d'une bibliothèque non migrée n’est jamais un frein. Au final, à part quelques débutants qui copient/collent sans réfléchir un bout de code fait pour une ancienne édition dans un projet qui utilise une édition plus récente, il n'y a eu quasiment aucun soucis.
flanker (./5017) :C'est vrai que c'est pas forcément un bon plan de forcer une communauté, mais entre mettre le couteau sous la gorge pour migrer immédiatement et supporter un double écosystème pendant plus de 11 ans, il y a un juste milieu. Je pense qu'un calendrier de transition sur 3 à 5 ans aurait pu passer. Le fait d'avoir une limite clairement définie dès le départ aurait insisté la communauté a faire rapidement la transition.[/quote]
C'est dangereux de forcer une communauté qui ne te doit rien. De plus, en pratique, à part quelques bibliothèques (surtout liées au réseau, qui manipulent souvent texte et chaînes binaires), la transition a été lente mais pas tant que ça. Ça fait très longtemps (au moins 8-9 ans) que je n'utilise plus que du Python 3.
Perso j'ai encore eu des problèmes à cause de scripts faits pour python 2 il n'y a pas si longtemps.Bah ça, quelque soit le langage ou la solution retenue, tu auras toujours des produits qui ne sont pas mis à jour.
flanker (./5020) :Alors je suis pas un expert python, loin de là donc n’hésite pas a me corriger si j'ai faux, mais de ce que j'avais compris, il est problématique de faire que un code conçu spécifiquement pour du Python 2 s’appuie sur des bibliothèques conçues spécifiquement pour du Python 3, et vice versa, sans modification spécifiques dans le code de l'un ou de l'autre. Rust n'a pas ce genre de problème : une crate (l'équivalent du package) a un numéro d'édition, ce qui permet au compilateur de savoir quelle syntaxe appliquer aux fichiers source. Le compilateur peut donc compiler et lier, des crates d'éditions différentes. Lors de la migration, on part d'un code clean dans l'édition précédente pour arriver a un code clean dans la nouvelle édition sans se soucier d'adapter le code pour conserver la rétro-compatibilité. Le fichier manifeste de la crate doit juste à déclarer son numéro d'édition, qui est initialisé à la dernière édition gérée par cargo (l'outil standard de build et de gestion des crate).
L'équivalent de ton exemple en Rust est un interpréteur Python qui peut interpréter mélanger du code Python 2 et du code Python 3, n'est-ce pas ? Ça tombe bien, c'est possible, au seul prix d'ajouter import __futures__.
Il n'est pas possible d'aller plus loin, ne serait-ce qu'à cause du problème str/unicode : dans de nombreux cas, ce qui est théoriquement la bonne solution (changer "" en b"") est souvent la mauvaise (car le développeur a eu la flemme de mettre u""). Je ne parle même pas des problèmes liés à la bibliothèque standard.
flanker (./5020) :Par ailleurs, ce que tu aurais souhaité aurait au contraire mécaniquement ralenti encore plus la transition qui a été déjà trop lente : si tu n'as aucune incitation à migrer ton code (vu que c'est transparent de le garder dans une vieille version), tu ne risques pas de le migrer.C'est vrai que l'incitation a migrer est moins forte, mais c'est aussi le cas de l'incitation à ne pas migrer. C'est beaucoup plus simple pour un mainteneur de crate de prendre la décision de migrer quand l'on sait qu'on aura pas besoin de se soucier de problèmes causés par les dépendances et qu'on en causera pas a ceux qui dépendent de nous. Dans la pratique quasiment toutes les crates Rust maintenues font la transition dans les mois qui suivent la sortie d'une édition.
Uther (./5023) :Si tous tes codes fonctionnent avec Python 2 et Python 3, il n'y a aucun souci à utiliser Python 2 ou Python 3. Mais c'est sûr qu'à partir du moment où un code utilise des spécificités de Python 2 ou 3, tu es obligé d'utiliser le bon interpréteur.
Alors je suis pas un expert python, loin de là donc n’hésite pas a me corriger si j'ai faux, mais de ce que j'avais compris, il est problématique de faire que un code conçu spécifiquement pour du Python 2 s’appuie sur des bibliothèques conçues spécifiquement pour du Python 3, et vice versa, sans modification spécifiques dans le code de l'un ou de l'autre.
Rust n'a pas ce genre de problème :[...]Il y a deux différences fondamentales : le côté compilé de Rust d'une part, et d'autre part Rust ne correspond qu'au langage (et éventuellement au compilo) alors que Python fait référence à la fois au langage, à l'interpréteur et à la bibliothèque standard.
flanker (./5020) :Par ailleurs, ce que tu aurais souhaité aurait au contraire mécaniquement ralenti encore plus la transition qui a été déjà trop lente : si tu n'as aucune incitation à migrer ton code (vu que c'est transparent de le garder dans une vieille version), tu ne risques pas de le migrer.C'est vrai que l'incitation a migrer est moins forte, mais c'est aussi le cas de l'incitation à ne pas migrer. [/quote]
C'est beaucoup plus simple pour un mainteneur de crate de prendre la décision de migrer quand l'on sait qu'on aura pas besoin de se soucier de problèmes causés par les dépendances et qu'on en causera pas a ceux qui dépendent de nous.Mais ce n'est pas faisable à cause de la bibliothèque standard.
Dans la pratique quasiment toutes les crates Rust maintenues font la transition dans les mois qui suivent la sortie d'une édition.Mais c'est pareil en Python : les codes activement maintenus font la migration très vite, sauf quelques rares exceptions (liées au réseau et le problème u"" / "", rendant la migration de grosses bases de code impossible à faire automatiquement et progressivement). Les passages de versions mineures sont généralement transparentes.
flanker (./5024) :Je ne pense pas que le coté compilé de Rust change grand chose au problème, on peut interpréter du Rust, tout comme on peut compiler du Python. Par contre je ne serais pas surpris que des fonctionnalités spécifiques du Python posent problème comme le typage dynamique. Je sais qu'en Rust certaines propriétés du système de type sont condamnées à rester comme elles sont pour que les traits définis dans une édition puissent être implémentés dans l'autre.
Il y a deux différences fondamentales : le côté compilé de Rust d'une part, et d'autre part Rust ne correspond qu'au langage (et éventuellement au compilo) alors que Python fait référence à la fois au langage, à l'interpréteur et à la bibliothèque standard.
flanker (./5024) :Ce que je veux surtout limiter dans la durée, c'est la situation ou on a deux dialectes parallèles pas directement compatibles. S'il n'y avait pas de problème d'incompatibilité, la situation ne me gênerait pas vraiment.
Tu reproches de ne pas avoir assez d'incitation à migrer en prolongeant le maintien de Python 2, et tu proposes d'encore moins inciter à migrer en gardant la compatibilité avec Python 2.
Uther (./5028) :Malheureusement, ce n'est pas possible de faire ça en Python à cause :
Même en compilant, on ne peut pas lier n'importe quel binaire avec n’importe quel autre : il faut qu'ils aient une ABI commune et Rust ne garantit pas, par défaut, la stabilité de l'ABI. On peut certes, comme en C++, utiliser ponctuellement l'ABI stable du C, mais c'est normalement juste pour permettre de s'interfacer avec d'autre langages car on limite les fonctionnalités comme les types génériques.
Pour faire fonctionner son système d’édition, Rust nécessite en effet que le compilateur sache traiter les deux dialectes, mais ça n'a rien d'insurmontable. Les deux édition ne sont différenciées qu'au niveau de l'analyse syntaxique et lexicale. Pour le reste de l'analyse et de la génération du binaire, le compilateur utilise diverses formes intermédiaires du code à compiler, communes à toutes les éditions. Rien n’empêche un interpréteur de faire de même. Les interpréteurs un minimum performant utilisent généralement déjà une ou plusieurs représentations intermédiaires.
Uther (./5030) :Non, parce que tu as un comportement fondamentalement différent.
Je vois pas trop pourquoi les string / bytes posent problème, c'est bien deux types différents qui peuvent être traités différemment non ? Si j'ai bien compris, les chaines littérales sont par défaut des byte en Python 2 et des strings en Python 3. Si un programme Python 3 pouvait faire appel, dans un module traité en tant que Python 2, à une variable non spécifiée comme String, il recevrait un byte qu'il devrait convertir s'il veut pouvoir l'utiliser en tant que String, et vice versa.
Quant à la bibliothèque standard, comme je l'ai dit plus haut, les composants changés auraient certainement pu être dépréciés et remplacés par des nouveaux.C'est rigolo, parce que tu râles sur la lenteur de la transition, et tu proposes plein de solutions pour qu'elle prenne encore plus de temps
flanker (./5032) :Je ne vois toujours pas en quoi le fonctionnement différent serait un point bloquant, je ne dis pas qu'il n'y a pas des particularités qui m'échappent quelque-part, mais l'exemple que tu donnes ne me parait pas particulièrement problématique.
Non, parce que tu as un comportement fondamentalement différent...
flanker (./5032) :C'est rigolo, parce que tu râles sur la lenteur de la transition, et tu proposes plein de solutions pour qu'elle prenne encore plus de tempsJe pense pas que la quantité de code modifié soit ce qui freine le plus une migration. Avec les outils d'assistance à la compatibilité, ça va assez vite.
Brunni (./5031) :Python peux « compiler » le code dans un bytecode (les fichier .pyc) et je doute que ça soit compatible entre P2 et P3, et je ne serait os surpris que même entre différentes versions de Python 3 il ne puisse pas y avoir des incompatibilités
Tu dois quand-même inclure deux versions de l'interpréteur si tu fais ça. Certes que la partie qui transforme le texte en forme intermédiaire (pour faire du JIT ; pas sûr que Python fasse ça d'ailleurs), mais c'est pas mal. Et pareil, la bibliothèque n'a pas grand chose en commun je crois. Mais quoi qu'il en soit je suis étonné qu'il n'y ait pas eu un fork qui fasse ça, ou qu'il n'ait pas pris.
Uther (./5033) :Ça veut quand même dire créer un interpréteur Python qui embarque à la fois Python 2 et Python 3. Très compliqué à faire techniquement, contraire à l'objectif de Python 3 (débarrasser Python des erreurs de Python 2), avec un intérêt somme toute très limité en pratique (la plupart des projets maintenus ont migré relativement rapidement). Et à nouveau, je ne vois pas comment cela aurait pu accélérer la transition : donner une solution pour rester encore plus longtemps à Python 2 n'est certainement pas une incitation à migrer.flanker (./5032) :Je ne vois toujours pas en quoi le fonctionnement différent serait un point bloquant, je ne dis pas qu'il n'y a pas des particularités qui m'échappent quelque-part, mais l'exemple que tu donnes ne me parait pas particulièrement problématique.
Non, parce que tu as un comportement fondamentalement différent...
Encore une fois, il ne s'agit pas de mélanger python 2 et 3 dans un même package. Un package serait soit en python 2 soit en python 3. C'est juste que des packages de versions majeures différentes pourraient être traités par le même interpréteur et interagir l'un avec l'autre. Mais l’intérieur d'un package Python 2, les règles de la version 2 s'appliqueraient (notamment pour la concaténation) alors que les package en version 3 appliqueraient leurs règles.
Ce qui est possiblement le plus problématique, c'est le système de type. Il faudrait s'assurer qu'il permet bien une interface entre du code en version 2 et 3.
flanker (./5032) :C'est rigolo, parce que tu râles sur la lenteur de la transition, et tu proposes plein de solutions pour qu'elle prenne encore plus de tempsJe pense pas que la quantité de code modifié soit ce qui freine le plus une migration. Avec les outils d'assistance à la compatibilité, ça va assez vite.
flanker (./5032) :Les principaux arguments que j'ai vu portaientSur les deux premiers points, en effet un système similaire aux éditions de Rust ne changerait probablement pas grand chose. Mais c'est plus un problème de qualité de l'existant que de migration.
- sur la complexité à migrer le bazar entre string/bytestring (et plus le code était gros, plus c'était compliqué),
- sur les bugs mis en évidence par Python 3, bugs de conception qu'il fallait donc corriger,
- sur l'absence en Python 3 de certaines dépendances critiques,
- sur le besoin de rester compatible avec les clients restant en Python 2.4 (coucou Ansible), avec plus ou moins de mauvaise foi d'ailleurs.