IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Python 3.11 est en moyenne 25 % plus rapide que 3.10


Sujet :

Python

  1. #1
    Chroniqueur Actualités
    Avatar de Bruno
    Homme Profil pro
    Rédacteur technique
    Inscrit en
    mai 2019
    Messages
    917
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Rédacteur technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2019
    Messages : 917
    Points : 10 949
    Points
    10 949
    Par défaut Python 3.11 est en moyenne 25 % plus rapide que 3.10
    Python 3.11 améliorera l'emplacement des erreurs dans les tracebacks,
    et apporte de nouvelles fonctionnalités

    L'équipe de développement de Python a annoncé le 4 octobre les améliorations et les nouvelles fonctionnalités de la version 3.11 de Python. Cette version améliore la localisation des erreurs dans les logs et optimise le formatage de style C avec un format littéral ne contenant que les codes de format %s, %r et %. Les compréhensions asynchrones sont maintenant autorisées à l'intérieur des compréhensions dans les fonctions asynchrones. Les compréhensions externes deviennent implicitement asynchrones.

    Python est un langage de programmation interprété, multi-paradigme et multi-plateformes. Il favorise la programmation impérative structurée, fonctionnelle et orientée objet. Il est doté d'un typage dynamique fort, d'une gestion automatique de la mémoire par ramasse-miettes et d'un système de gestion d'exceptions ; il est ainsi similaire à Perl, Ruby, Scheme, Smalltalk et Tcl.

    Nom : python.png
Affichages : 127184
Taille : 3,4 Ko

    Le langage Python est placé sous une licence libre proche de la licence BSD et fonctionne sur la plupart des plateformes informatiques, des smartphones aux ordinateurs, de Windows à Unix avec notamment GNU/Linux en passant par macOS, ou encore Android, iOS, et peut aussi être traduit en Java ou .NET. Il est conçu pour optimiser la productivité des programmeurs en offrant des outils de haut niveau et une syntaxe simple à utiliser. Voici, ci-dessous, quelques nouveautés apportées par la version 3.11 de Python.

    Amélioration de la localisation des erreurs dans les logs

    Lors de l'impression des traces, l'interpréteur pointe désormais vers l'expression exacte qui a causé l'erreur au lieu de la ligne. Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Traceback (most recent call last):
      File "distance.py", line 11, in <module>
        print(manhattan_distance(p1, p2))
              ^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "distance.py", line 6, in manhattan_distance
        return abs(point_1.x - point_2.x) + abs(point_1.y - point_2.y)
                               ^^^^^^^^^
    AttributeError: 'NoneType' object has no attribute 'x'
    Les versions précédentes de l'interpréteur ne pointaient que sur la ligne, ce qui rendait ambiguë la question de savoir quel objet était None. Ces erreurs améliorées peuvent également être utiles lorsqu'il s'agit d'objets de dictionnaire profondément imbriqués et d'appels de fonction multiples,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Traceback (most recent call last):
      File "query.py", line 37, in <module>
        magic_arithmetic('foo')
        ^^^^^^^^^^^^^^^^^^^^^^^
      File "query.py", line 18, in magic_arithmetic
        return add_counts(x) / 25
               ^^^^^^^^^^^^^
      File "query.py", line 24, in add_counts
        return 25 + query_user(user1) + query_user(user2)
                    ^^^^^^^^^^^^^^^^^
      File "query.py", line 32, in query_user
        return 1 + query_count(db, response['a']['b']['c']['user'], retry=True)
                                   ~~~~~~~~~~~~~~~~~~^^^^^
    TypeError: 'NoneType' object is not subscriptable

    Modules améliorés

    maths

    • ajout de math.cbrt() : retourne la racine cubique de x ;
    • le comportement de deux cas particuliers de math.pow() a été modifié, par souci de cohérence avec la spécification IEEE 754. Les opérations math.pow(0.0, -math.inf) et math.pow(-0.0, -math.inf) retournent maintenant inf. Auparavant, elles indiquaient ValueError.

    opérateur
    Une nouvelle fonction operator.call a été ajoutée, telle que operator.call(obj, *args, **kwargs) == obj(*args, **kwargs).

    Système d’exploitation

    Sous Windows, os.urandom() utilise maintenant BCryptGenRandom(), au lieu de CryptGenRandom() qui est déprécié.

    sqlite3

    • il est maintenant possible de désactiver l'authorizer en passant None à set_authorizer() ;
    • le nom de collation create_collation() peut maintenant contenir n'importe quel caractère Unicode. Les noms de collation avec des caractères non valides indiquent maintenant UnicodeEncodeError au lieu de sqlite3.ProgrammingError ;
    • les exceptions sqlite3 incluent maintenant le code d'erreur SQLite comme sqlite_errorcode et le nom de l'erreur SQLite comme sqlite_errorname.

    threading

    • Sous Unix, si la fonction sem_clockwait() est disponible dans la bibliothèque C (glibc 2.30 et plus récent), la méthode threading.Lock.acquire() utilise maintenant l'horloge monotonique (time.CLOCK_MONOTONIC) pour le délai d'attente, plutôt que d'utiliser l'horloge système (time.CLOCK_REALTIME), pour ne pas être affecté par les changements d'horloge système ;
    • Sous Unix, time.sleep() utilise désormais la fonction clock_nanosleep() ou nanosleep(), si elle est disponible, qui a une résolution de 1 nanoseconde (10-9 secondes), plutôt que d'utiliser select() qui a une résolution de 1 microseconde (10-6 secondes) ;
    • Sous Windows, time.sleep() utilise désormais un timer waitable dont la résolution est de 100 nanosecondes (10-7 secondes). Auparavant, il avait une résolution de 1 milliseconde (10-3 secondes).

    Portage vers Python 3.11

    Les anciennes macros (Py_TRASHCAN_SAFE_BEGIN/Py_TRASHCAN_SAFE_END) sont désormais obsolètes. Elles doivent être remplacées par les nouvelles macros Py_TRASHCAN_BEGIN et Py_TRASHCAN_END.
    Les anciennes macros, telles que :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    static void
    mytype_dealloc(mytype *p)
    {
        PyObject_GC_UnTrack(p);
        Py_TRASHCAN_SAFE_BEGIN(p);
        ...
        Py_TRASHCAN_SAFE_END
    }
    doivent migrer vers les nouvelles macros comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    static void
    mytype_dealloc(mytype *p)
    {
        PyObject_GC_UnTrack(p);
        Py_TRASHCAN_BEGIN(p, mytype_dealloc)
        ...
        Py_TRASHCAN_END
    }
    Optimisations

    • le compilateur optimise maintenant le formatage simple de style C avec un format littéral contenant seulement les codes de format %s, %r et %a et le rend aussi rapide que l'expression f-string correspondante ;
    • les exceptions "à coût zéro" sont implémentées. Le coût des instructions try est pratiquement éliminé lorsqu'aucune exception n'est levée ;
    • les appels de méthodes avec des mots-clés sont maintenant plus rapides grâce à des modifications du bytecode qui évitent de créer des instances de méthodes liées. Auparavant, cette optimisation n'était appliquée qu'aux appels de méthodes avec des arguments purement positionnels.

    Source : Python

    Et vous ?

    Quel est votre avis sur le sujet ?

    Quel amélioration vous intéresse le plus ?

    Voir aussi :

    Django 3.1 est disponible, compatible avec Python 3.6, 3.7 et 3.8 et introduit JSONField pour tous les backends de base de données supportés

    La version 3.2 du framework Django est disponible, avec la découverte automatique d'AppConfig, elle apporte de nouveaux décorateurs pour le module d'administration

    Django 2.0 est disponible en version stable, quelles sont les nouveautés dans cette version du framework Web écrit en Python ?

    JetBrains soutient Django : bénéficiez d'une remise de 30 % pour l'achat d'une licence individuelle PyCharm Professional et l'intégralité des sommes perçues seront reversées à la Fondation Django
    Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    19 694
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2008
    Messages : 19 694
    Points : 34 038
    Points
    34 038
    Par défaut
    Salut,

    Citation Envoyé par Bruno Voir le message
    Et vous ?

    Quel est votre avis sur le sujet ?
    Une version beta-test n'est pas "disponible" et même la version 3.10 n'est pas encore sortie "officiellement" (toujours en tests). A ce stade, il n'est pas exclu que certaines fonctionnalités annoncées soient retirées, quelques mineures ajoutées,...

    Et en l'état, seuls les développeurs qui ont le temps (et des environnements) pour faire des tests de non-régression ou très intéressés par quelques unes des nouvelles fonctionnalités vont y passer du temps.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre éclairé Avatar de jvallois
    Homme Profil pro
    Enseignant
    Inscrit en
    février 2013
    Messages
    161
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Aisne (Picardie)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : février 2013
    Messages : 161
    Points : 836
    Points
    836
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Une version beta-test n'est pas "disponible" et même la version 3.10 n'est pas encore sortie "officiellement" (toujours en tests). A ce stade, il n'est pas exclu que certaines fonctionnalités annoncées soient retirées, quelques mineures ajoutées,...
    Tout à fait d'accord, sauf pour un point : la 3.10 est disponible depuis aujourd'hui : https://www.python.org/downloads/

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    juin 2008
    Messages
    19 694
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : juin 2008
    Messages : 19 694
    Points : 34 038
    Points
    34 038
    Par défaut
    Citation Envoyé par jvallois Voir le message
    Tout à fait d'accord, sauf pour un point : la 3.10 est disponible depuis aujourd'hui : https://www.python.org/downloads/
    Quand j'ai regardé hier, elle ne l'était pas encore.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre à l'essai
    Homme Profil pro
    indépendant
    Inscrit en
    mai 2016
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : indépendant

    Informations forums :
    Inscription : mai 2016
    Messages : 12
    Points : 20
    Points
    20
    Par défaut C'est bien cette meilleure localisation des erreurs, on va apprécier A+
    A+

  6. #6
    Chroniqueur Actualités
    Avatar de Bruno
    Homme Profil pro
    Rédacteur technique
    Inscrit en
    mai 2019
    Messages
    917
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Rédacteur technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2019
    Messages : 917
    Points : 10 949
    Points
    10 949
    Par défaut Python 3.11 gagnera en performance au prix d'un peu plus de mémoire
    Python 3.11 gagnera en performance au prix d'un peu plus de mémoire,
    les gains de vitesse semblent se situer entre 10 % et 60 %

    Dans le but d’améliorer les performances du langage de programmation Python, Microsoft lance Faster CPython. Il s’agit d’un projet financé par Microsoft, dont les membres comprennent l'inventeur de Python Guido van Rossum, l'ingénieur logiciel senior de Microsoft Eric Snow, et Mark Shannon qui est sous contrat avec Microsoft en tant que responsable technique du projet. « Python est largement reconnu comme étant lent. Alors que Python n'atteindra jamais les performances des langages de bas niveau comme C, Fortran, ou même Java, nous aimerions qu'il soit compétitif avec les implémentations rapides des langages de script, comme V8 pour Javascript », déclare Mark Shannon.

    Pour être performantes, les machines virtuelles pour les langages dynamiques doivent spécialiser le code qu'elles exécutent en fonction des types et des valeurs du programme en cours d'exécution. Cette spécialisation est souvent associée aux compilateurs Just-in-time (JIT), mais elle est bénéfique même sans génération de code machine.

    Nom : python.png
Affichages : 56915
Taille : 3,1 Ko

    Notons que la spécialisation permet d'améliorer les performances, et l'adaptation permet à l'interprète de changer rapidement lorsque le modèle d'utilisation d'un programme change, limitant ainsi la quantité de travail supplémentaire causée par une mauvaise spécialisation.

    Une session prévue dans le cadre de l'événement EuroPython, la plus grande conférence Python en Europe, qui se tiendra à Dublin en juillet sera consacrée à certains des changements qui permettent d'accélérer le processus. Shannon décrira l'adaptive specializing interpreter de Python 3.11, qui est le PEP (Python Enhancement Proposal) 659. Il s'agit d'une technique appelée spécialisation qui, comme l'explique Shannon, « est généralement réalisée dans le contexte d'un compilateur, mais la recherche montre que la spécialisation dans un interpréteur peut augmenter les performances de manière significative ».

    Ce PEP propose d'utiliser un interprète adaptatif qui spécialise le code de manière dynamique, mais sur une très petite région, et qui est capable de s'adapter à une mauvaise spécialisation rapidement et à faible coût.

    « L'ajout d'un interprète spécialisé et adaptatif à CPython apportera des améliorations significatives en termes de performances. Il est difficile d'avancer des chiffres significatifs, car cela dépend beaucoup des benchmarks et de travaux qui n'ont pas encore été réalisés. Des expérimentations approfondies suggèrent des accélérations allant jusqu'à 50 %. Même si le gain de vitesse n'était que de 25 %, cela resterait une amélioration intéressante », déclare Shannon.

    « Plus précisément, nous voulons atteindre ces objectifs de performance avec CPython afin d'en faire bénéficier tous les utilisateurs de Python, y compris ceux qui ne peuvent pas utiliser PyPy ou d'autres machines virtuelles alternatives », ajoute-il. Lorsque Devclass s'est entretenu avec Pablo Galindo, membre du conseil de direction de Python et développeur principal, au sujet du nouveau profileur de mémoire Memray, il a décrit comment l'équipe Python utilise le travail de Microsoft dans la version 3.11.

    « L'une des choses que nous faisons est que nous rendons l'interpréteur plus rapide, déclare Pablo Galindo, membre du conseil de direction de Python et développeur principal. Mais il va également utiliser un peu plus de mémoire, juste un peu, parce que la plupart de ces optimisations ont une sorte de coût en mémoire, étant donné que nous devons stocker des choses pour les utiliser plus tard, ou parce que nous avons une version optimisée mais parfois, quelqu'un a besoin de demander une version non optimisée pour le débogage, donc nous devons stocker les deux. »

    « Atteindre ces objectifs de performance est un long chemin à parcourir, et nécessitera beaucoup d'efforts d'ingénierie, mais nous pouvons faire un pas significatif vers ces objectifs en accélérant l'interpréteur. La recherche universitaire et les mises en œuvre pratiques ont montré qu'un interpréteur rapide est un élément clé d'une machine virtuelle rapide », déclare Shannon.

    Accélération des machines virtuelles

    Les optimisations typiques pour les machines virtuelles sont coûteuses, de sorte qu'un long temps de "démarrage" est nécessaire pour avoir la certitude que le coût de l'optimisation est justifié. Afin d'obtenir des accélérations rapides, sans temps d'échauffement perceptible, la VM devrait spéculer que la spécialisation est justifiée même après quelques exécutions d'une fonction. Pour ce faire, l'interpréteur doit être capable d'optimiser et de désoptimiser continuellement et à moindre coût. En utilisant la spécialisation adaptative et spéculative à la granularité des instructions individuelles de la machine virtuelle, l’équipe Python a obtenu un interprète plus rapide qui génère également des informations de profilage pour des optimisations plus sophistiquées dans le futur.

    « Il existe de nombreuses façons pratiques d'accélérer une machine virtuelle pour un langage dynamique. Cependant, la spécialisation est la plus importante, à la fois en elle-même et en tant que catalyseur d'autres optimisations. Il est donc logique de concentrer nos efforts sur la spécialisation en premier lieu, si nous voulons améliorer les performances de CPython », indique l’équipe du projet Faster CPython. La spécialisation est généralement effectuée dans le contexte d'un compilateur JIT, mais des recherches montrent que la spécialisation dans un interpréteur peut améliorer les performances de manière significative, voire même dépasser celles d'un compilateur classique.

    Plusieurs méthodes ont été proposées dans la littérature académique, mais la plupart tentent d'optimiser des domaines plus grands qu'un seul bytecode. L'utilisation de domaines plus grands qu'une seule instruction nécessite un code pour gérer la désoptimisation au milieu d'un domaine. La spécialisation au niveau des bytecodes individuels rend la désoptimisation triviale, car elle ne peut pas se produire au milieu d'une région.

    En spécialisant de manière spéculative les bytecodes individuels, nous pouvons obtenir des améliorations de performance significatives sans rien d'autre que les désoptimisations les plus locales et triviales à mettre en œuvre. L'approche la plus proche de ce PEP dans la littérature est "Inline Caching meets Quickening". Ce PEP présente les avantages de la mise en cache en ligne, mais ajoute la possibilité de désoptimiser rapidement, ce qui rend les performances plus robustes dans les cas où la spécialisation échoue ou n'est pas stable.

    L'accélération due à la spécialisation est difficile à déterminer, car de nombreuses spécialisations dépendent d'autres optimisations. Les gains de vitesse semblent se situer entre 10 % et 60 %. La plupart des gains de vitesse proviennent directement de la spécialisation. Les plus grands contributeurs étant les accélérations de la recherche d'attributs, des variables globales et des appels.

    Implémentation

    Instructions adaptatives

    Chaque instruction qui bénéficierait d'une spécialisation est remplacée par une version adaptative lors du quickening. Par exemple, l'instruction LOAD_ATTR est remplacée par LOAD_ATTR_ADAPTIVE. Chaque instruction adaptative tente périodiquement de se spécialiser.

    Spécialisation

    Le bytecode CPython contient de nombreuses instructions qui représentent des opérations de haut niveau, et qui bénéficieraient d'une spécialisation. Les exemples incluent CALL, LOAD_ATTR, LOAD_GLOBAL et BINARY_ADD.

    L'introduction d'une catégorie d'instructions spécialisées pour chacune de ces instructions permet une spécialisation efficace, puisque chaque nouvelle instruction est spécialisée pour une seule tâche. Chaque famille comprendra une instruction "adaptative", qui maintient un compteur et tente de se spécialiser lorsque ce compteur atteint zéro. Chaque catégorie comprendra également une ou plusieurs instructions spécialisées qui exécutent l'équivalent de l'opération générique beaucoup plus rapidement, à condition que leurs entrées soient conformes aux prévisions.

    Chaque instruction spécialisée maintient un compteur de saturation qui est incrémenté lorsque les entrées sont conformes aux attentes. Si les entrées ne sont pas conformes aux attentes, le compteur sera décrémenté et l'opération générique sera exécutée. Si le compteur atteint la valeur minimale, l'instruction est désoptimisée en remplaçant simplement son opcode par la version adaptative.

    Données auxiliaires

    La plupart des familles d'instructions spécialisées requièrent plus d'informations que ne peut en contenir un opérande de 8 bits. Pour ce faire, un certain nombre d'entrées de 16 bits suivant immédiatement l'instruction sont utilisées pour stocker ces données. Il s'agit d'une forme de cache en ligne, un "cache de données en ligne". Les instructions non spécialisées, ou adaptatives, utiliseront la première entrée de ce cache comme compteur, et sauteront simplement les autres.

    Coûts

    Utilisation de la mémoire

    Une préoccupation évidente avec tout système qui effectue une sorte de mise en cache est : combien de mémoire supplémentaire utilise-t-il ?

    Comparaison de l'utilisation de la mémoire avec 3.10

    CPython 3.10 utilisait 2 octets par instruction, jusqu'à ce que le nombre d'exécutions atteigne ~2000 lorsqu'il alloue un autre octet par instruction et 32 octets par instruction avec un cache (LOAD_GLOBAL et LOAD_ATTR).

    Le tableau suivant montre les octets supplémentaires par instruction pour supporter l'opcache 3.10 ou l'interprète adaptatif proposé, sur une machine 64 bits.

    Nom : hot.png
Affichages : 3043
Taille : 15,4 Ko

    3.10 cold est avant que le code n'ait atteint la limite de ~2000. 3.10 hot montre l'utilisation du cache une fois que le seuil est atteint. L'utilisation relative de la mémoire dépend de la quantité de code qui est suffisamment "hot" pour déclencher la création du cache dans 3.10. Le point d'équilibre, où la mémoire utilisée par 3.10 est la même que pour 3.11, est de ~70%. Il convient également de noter que le bytecode réel n'est qu'une partie d'un objet de code. Les objets de code comprennent également des noms, des constantes et un grand nombre d'informations de débogage.

    En résumé, pour la plupart des applications où de nombreuses fonctions sont relativement inutilisées, la version 3.11 consommera plus de mémoire que la version 3.10.

    Source : Python

    Et vous ?

    Quel est votre avis sur le sujet ?

    Que pensez-vous du projet Faster CPython ?

    « La version 3.11 consommera plus de mémoire que la version 3.10 », qu’en pensez-vous ?

    Selon vous, est intéressent de gagner en performance au prix d'un peu plus de mémoire ?

    Voir aussi :

    Python 3.11 améliorera l'emplacement des erreurs dans les tracebacks et apporte de nouvelles fonctionnalités

    La version 3.2 du framework Django est disponible, avec la découverte automatique d'AppConfig, elle apporte de nouveaux décorateurs pour le module d'administration

    Django 2.0 est disponible en version stable, quelles sont les nouveautés dans cette version du framework Web écrit en Python ?

    JetBrains soutient Django : bénéficiez d'une remise de 30 % pour l'achat d'une licence individuelle PyCharm Professional et l'intégralité des sommes perçues seront reversées à la Fondation Django
    Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

  7. #7
    Chroniqueur Actualités

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    mars 2013
    Messages
    7 030
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : mars 2013
    Messages : 7 030
    Points : 158 764
    Points
    158 764
    Par défaut La première version bêta de Python 3.11 est disponible et s'accompagne d'une meilleure gestion des erreurs
    La première version bêta de Python 3.11 est disponible et s'accompagne d'une meilleure gestion des erreurs,
    de la prise en charge de toml et d'améliorations pour la programmation asynchrone

    Meilleure gestion des erreurs

    Python 3.10 nous a donné de meilleurs messages d'erreur à divers égards, mais Python 3.11 vise à les améliorer encore plus. Certaines des choses les plus importantes qui sont ajoutées aux messages d'erreur dans Python 3.11 sont :

    Emplacements exacts des erreurs dans les retraçages

    Jusqu'à présent, dans un traçage, la seule information que vous obteniez sur l'endroit où une exception a été déclenchée était la ligne. Le problème aurait pu être n'importe où sur la ligne, donc parfois cette information n'était pas suffisante.

    Voici un exemple*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def get_margin(data):
        margin = data['profits']['monthly'] / 10 + data['profits']['yearly'] / 2
        return margin
     
    data = {
        'profits': {
            'monthly': 0.82,
            'yearly': None,
        },
        'losses': {
            'monthly': 0.23,
            'yearly': 1.38,
        },
    }
    print(get_margin(data))

    Ce code génère une erreur, car l'un de ces champs dans le dictionnaire est None. Voici ce que nous obtenons*:

    Citation Envoyé par Affichage à l'écran
    Traceback (most recent call last):
    File "/Users/tusharsadhwani/code/marvin-python/mytest.py", line 15, in <module>
    print(get_margin(data))
    File "/Users/tusharsadhwani/code/marvin-python/mytest.py", line 2, in print_margin
    margin = data['profits']['monthly'] / 10 + data['profits']['yearly'] / 2
    TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'
    Mais il est impossible de dire par le retraçage lui-même, quelle partie du calcul a causé l'erreur.

    Sur la version 3.11 cependant :

    Citation Envoyé par Affichage à l'écran
    Traceback (most recent call last):
    File "asd.py", line 15, in <module>
    print(get_margin(data))
    ^^^^^^^^^^^^^^^^
    File "asd.py", line 2, in print_margin
    margin = data['profits']['monthly'] / 10 + data['profits']['yearly'] / 2
    ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~
    TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'
    Il est évident que data['profits']['yearly'] était None.

    Pour pouvoir restituer ces informations, les données end_line et end_col ont été ajoutées aux objets de code Python. Vous pouvez également accéder à ces informations directement via la méthode obj.__code__.co_positions().

    Les notes pour les exceptions

    Pour rendre les traces encore plus riches en contexte, Python 3.11 vous permet d'ajouter des notes aux objets d'exception, qui sont stockées dans les exceptions et affichées lorsque l'exception est déclenchée.

    Prenez ce code par exemple, où nous ajoutons des informations importantes sur une logique de conversion de données d'API*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def get_seconds(data):
        try:
            milliseconds = float(data['milliseconds'])
        except ValueError as exc:
            exc.add_note(
                "The time field should always be a number, this is a critial bug. "
                "Please report this to the backend team immediately."
            )
            raise  # re-raises the exception, instead of silencing it
     
        seconds = milliseconds / 1000
        return seconds
     
    get_seconds({'milliseconds': 'foo'})  # 'foo' is not a number!

    Cette note ajoutée est imprimée juste en dessous du message d'exception*:

    Citation Envoyé par Affichage à l'écran
    Traceback (most recent call last):
    File "asd.py", line 14, in <module>
    get_seconds({"milliseconds": "foo"})
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "asd.py", line 3, in get_seconds
    milliseconds = float(data["milliseconds"])
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ValueError: could not convert string to float: 'foo'
    The time field should always be a number, this is a critial bug. Please report this to the backend team immediately.
    Prise en charge toml intégrée

    La bibliothèque standard a maintenant un support intégré pour lire les fichiers TOML, en utilisant le module tomllib*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    import tomllib
     
    with open('.deepsource.toml', 'rb') as file:
        data = tomllib.load(file)

    tomllib est en fait basé sur une bibliothèque d'analyse TOML open source appelée tomli. Et actuellement, seule la lecture des fichiers TOML est prise en charge. Si vous devez plutôt écrire des données dans un fichier TOML, envisagez d'utiliser le package tomli-w.

    Groupes de travail asynchrones

    Lorsque vous faites de la programmation asynchrone, vous rencontrez souvent des situations où vous devez déclencher de nombreuses tâches à exécuter simultanément, puis prendre des mesures lorsqu'elles sont terminées. Par exemple, télécharger un tas d'images en parallèle, puis les regrouper dans un fichier zip à la fin.

    Pour ce faire, vous devez collecter des tâches et les transmettre à asyncio.gather. Voici un exemple simple de tâches exécutées en parallèle avec la fonction de gather*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import asyncio
     
    async def simulate_flight(city, departure_time, duration):
        await asyncio.sleep(departure_time)
        print(f"Flight for {city} departing at {departure_time}PM")
     
        await asyncio.sleep(duration)
        print(f"Flight for {city} arrived.")
     
     
    flight_schedule = {
        'boston': [3, 2],
        'detroit': [7, 4],
        'new york': [1, 9],
    }
     
    async def main():
        tasks = []
        for city, (departure_time, duration) in flight_schedule.items():
            tasks.append(simulate_flight(city, departure_time, duration))
     
        await asyncio.gather(*tasks)
        print("Simulations done.")
     
    asyncio.run(main())

    Mais devoir maintenir une liste des tâches soi-même pour pouvoir les attendre est un peu maladroit. Aussi, une nouvelle API est ajoutée à asyncio appelée Groupes de tâches*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import asyncio
     
    async def simulate_flight(city, departure_time, duration):
        await asyncio.sleep(departure_time)
        print(f"Flight for {city} departing at {departure_time}PM")
     
        await asyncio.sleep(duration)
        print(f"Flight for {city} arrived.")
     
     
    flight_schedule = {
        'boston': [3, 2],
        'detroit': [7, 4],
        'new york': [1, 9],
    }
     
    async def main():
        async with asyncio.TaskGroup() as tg:
            for city, (departure_time, duration) in flight_schedule.items():
                tg.create_task(simulate_flight(city, departure_time, duration))
     
        print("Simulations done.")
     
    asyncio.run(main())

    Lorsque le gestionnaire de contexte asyncio.TaskGroup() se ferme, il s'assure que toutes les tâches créées à l'intérieur ont fini de s'exécuter.

    Nom : python.png
Affichages : 8745
Taille : 12,5 Ko

    Groupes d'exceptions

    Une fonctionnalité similaire a également été ajoutée pour la gestion des exceptions dans les tâches asynchrones, appelées groupes d'exceptions.

    Supposons que de nombreuses tâches asynchrones s'exécutent ensemble et que certaines d'entre elles génèrent des erreurs. Actuellement, le système de gestion des exceptions de Python ne fonctionne pas bien dans ce scénario.

    Voici une courte démo de ce à quoi cela ressemble avec 3 tâches simultanées qui ont planté*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import asyncio
     
    def bad_task():
        raise ValueError("oops")
     
    async def main():
        tasks = []
        for _ in range(3):
            tasks.append(asyncio.create_task(bad_task()))
     
        await asyncio.gather(*tasks)
     
    asyncio.run(main())

    Lorsque vous exécutez ce code*:

    Citation Envoyé par Affichage à l'écran
    $ python asd.py
    Traceback (most recent call last):
    File "asd.py", line 13, in <module>
    asyncio.run(main())
    File "/usr/bin/python3.8/lib/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
    File "/usr/bin/python3.8/lib/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
    File "asd.py", line 9, in main
    tasks.append(asyncio.create_task(bad_task()))
    File "asd.py", line 4, in bad_task
    raise ValueError("oops")
    ValueError: oops
    Rien n'indique que 3 de ces tâches s'exécutaient ensemble. Dès que la première échoue, elle fait planter tout le programme.

    Mais en Python 3.11, le comportement est un peu meilleur*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import asyncio
     
    async def bad_task():
        raise ValueError("oops")
     
    async def main():
        async with asyncio.TaskGroup() as tg:
            for _ in range(3):
                tg.create_task(bad_task())
     
    asyncio.run(main())

    Citation Envoyé par Affichage à l'écran
    $ python asd.py
    + Exception Group Traceback (most recent call last):
    | File "<stdin>", line 1, in <module>
    | File "/usr/local/lib/python3.11/asyncio/runners.py", line 181, in run
    | return runner.run(main)
    | ^^^^^^^^^^^^^^^^
    | File "/usr/local/lib/python3.11/asyncio/runners.py", line 115, in run
    | return self._loop.run_until_complete(task)
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    | File "/usr/local/lib/python3.11/asyncio/base_events.py", line 650, in run_until_complete
    | return future.result()
    | ^^^^^^^^^^^^^^^
    | File "<stdin>", line 2, in main
    | File "/usr/local/lib/python3.11/asyncio/taskgroups.py", line 139, in __aexit__
    | raise me from None
    | ^^^^^^^^^^^^^^^^^^
    | ExceptionGroup: unhandled errors in a TaskGroup (3 sub-exceptions)
    +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    | File "<stdin>", line 2, in bad_task
    | ValueError: oops
    +---------------- 2 ----------------
    | Traceback (most recent call last):
    | File "<stdin>", line 2, in bad_task
    | ValueError: oops
    +---------------- 3 ----------------
    | Traceback (most recent call last):
    | File "<stdin>", line 2, in bad_task
    | ValueError: oops
    +------------------------------------
    L'exception nous indique maintenant que trois erreurs ont été générées, dans une structure appelée ExceptionGroup.

    La gestion des exceptions avec ces groupes d'exceptions est également intéressante, vous pouvez soit faire except ExceptionGroup pour intercepter toutes les exceptions en une seule fois :

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    try:
        asyncio.run(main())
    except ExceptionGroup as eg:
        print(f"Caught exceptions: {eg}")

    Citation Envoyé par Affichage à l'écran
    $ python asd.py
    Caught exceptions: unhandled errors in a TaskGroup (3 sub-exceptions)
    Ou vous pouvez les intercepter en fonction du type d'exception, en utilisant la nouvelle syntaxe except**:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    try:
        asyncio.run(main())
    except* ValueError as eg:
        print(f"Caught ValueErrors: {eg}")

    Citation Envoyé par Affichage à l'écran
    $ python asd.py
    Caught ValueErrors: unhandled errors in a TaskGroup (3 sub-exceptions)
    Améliorations apportées au module typing

    Le module typing a vu beaucoup de mises à jour intéressantes dans cette version. Voici quelques-uns des plus intéressantes :

    Génériques variadiques

    La prise en charge des génériques variadiques a été ajoutée au module typing dans Python 3.11.

    Cela signifie que vous pouvez désormais définir des types génériques pouvant contenir un nombre arbitraire de types. Il est utile pour définir des méthodes génériques pour les données multidimensionnelles.

    Par exemple:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    from typing import Generic
    from typing_extensions import TypeVarTuple, Unpack
     
    Shape = TypeVarTuple('Shape')
     
    class Array(Generic[Unpack[Shape]]):
        ...
     
    # holds 1 dimensional data, like a regular list
    items: Array[int] = Array()
     
    # holds 3 dimensional data, for example, X axis, Y axis and value
    market_prices: Array[int, int, float] = Array()
     
    # This function takes in an `Array` of any shape, and returns the same shape
    def double(array: Array[Unpack[Shape]]) -> Array[Unpack[Shape]]:
        ...
     
    # This function takes an N+2 dimensional array and reduces it to an N dimensional one
    def get_values(array: Array[int, int, *Shape]) -> Array[*Shape]:
        ...
     
    # For example:
    vector_space: Array[int, int, complex] = Array()
    reveal_type(get_values(vector_space))  # revealed type is Array[complex]

    Les génériques variadiques peuvent être très utiles pour définir des fonctions qui mappent sur des données à N dimensions. Cette fonctionnalité peut être très utile pour la vérification de type des bases de code qui s'appuient sur des bibliothèques de science des données telles que numpy ou tensorflow.

    L'équipe responsable du développement de Python explique que : « La nouvelle syntaxe Generic[*Shape] n'est prise en charge que dans Python 3.11. Pour utiliser cette fonctionnalité dans Python 3.10 et versions antérieures, vous pouvez utiliser la fonction intégrée typing.Unpack à la place de Generic[Unpack[Shape]] ».

    singledispatch prend désormais en charge les unions

    functools.singledispatch est un moyen pratique de surcharger les fonctions en Python, basé sur des indications de type. Cela fonctionne en définissant une fonction générique et en se servant de @singledispatch. Ensuite, vous pouvez définir des variantes spécialisées de cette fonction, en fonction du type des arguments de la fonction*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    from functools import singledispatch
     
     
    @singledispatch
    def half(x):
        """Returns the half of a number"""
        return x / 2
     
    @half.register
    def _(x: int):
        """For integers, return an integer"""
        return x // 2
     
    @half.register
    def _(x: list):
        """For a list of items, get the first half of it."""
        list_length = len(x)
        return x[: list_length // 2]
     
                                # Outputs:
    print(half(3.6))            # 1.8
    print(half(15))             # 7
    print(half([1, 2, 3, 4]))   # [1, 2]

    En inspectant le type donné aux arguments de la fonction, singledispatch peut créer des fonctions génériques, fournissant une manière non orientée objet de faire la surcharge de fonction.

    Mais ce sont toutes de vieilles nouvelles. Ce que Python 3.11 apporte, c'est que maintenant, vous pouvez passer des types d'union pour ces arguments. Par exemple, pour enregistrer une fonction pour tous les types de nombres, vous deviez auparavant le faire séparément pour chaque type, tel que float, complex ou Decimal :

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @half.register
    def _(x: float):
        return x / 2
     
    @half.register
    def _(x: complex):
        return x / 2
     
    @half.register
    def _(x: decimal.Decimal):
        return x / 2

    Mais maintenant, vous pouvez tous les spécifier dans une Union*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    @half.register
    def _(x: float | complex | decimal.Decimal):
        return x / 2

    Et le code fonctionnera exactement comme prévu.

    Le type self

    Auparavant, si vous deviez définir une méthode de classe qui renvoyait un objet de la classe elle-même, ajouter des types pour cela était un peu bizarre, cela ressemblerait à ceci*:

    Code TypeScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    from typing import TypeVar
     
    T = TypeVar('T', bound=type)
     
    class Circle:
        def __init__(self, radius: int) -> None:
            self.radius = radius
     
        @classmethod
        def from_diameter(cls: T, diameter) -> T:
            circle = cls(radius=diameter/2)
            return circle

    Pour pouvoir dire qu'une méthode retourne le même type que la classe elle-même, il fallait définir un TypeVar, et dire que la méthode retourne le même type T que la classe actuelle elle-même.

    Mais avec le type Self, rien de tout cela n'est nécessaire*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from typing import Self
     
    class Circle:
        def __init__(self, radius: int) -> None:
            self.radius = radius
     
        @classmethod
        def from_diameter(cls, diameter) -> Self:
            circle = cls(radius=diameter/2)
            return circle

    Required[] and NotRequired[]

    TypedDict est vraiment utile pour ajouter des informations de type à une base de code qui utilise beaucoup de dictionnaires pour stocker des données. Voici comment vous pouvez les utiliser*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    from typing import TypedDict
     
    class User(TypedDict):
        name: str
        age: int
     
    user : User = {'name': "Alice", 'age': 31}
    reveal_type(user['age'])  # revealed type is 'int'

    Cependant, TypedDicts avait une limitation, où vous ne pouviez pas avoir de paramètres facultatifs dans un dictionnaire, un peu comme les paramètres par défaut dans les définitions de fonction.

    Par exemple, vous pouvez le faire avec un NamedTuple*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    from typing import NamedTuple
     
    class User(NamedTuple):
        name: str
        age: int
        married: bool = False
     
    marie = User(name='Marie', age=29, married=True)
    fredrick = User(name='Fredrick', age=17)  # 'married' is False by default

    Cela n'était pas possible avec un TypedDict (au moins sans définir plusieurs de ces types TypedDict). Mais maintenant, vous pouvez marquer n'importe quel champ comme NotRequired, pour signaler qu'il est normal que le dictionnaire n'ait pas ce champ*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    from typing import TypedDict, NotRequired
     
    class User(TypedDict):
        name: str
        age: int
        married: NotRequired[bool]
     
    marie: User = {'name': 'Marie', 'age': 29, 'married': True}
    fredrick : User = {'name': 'Fredrick', 'age': 17}  # 'married' is not required

    NotRequired est plus utile lorsque la plupart des champs de votre dictionnaire sont obligatoires, avec quelques champs non obligatoires. Mais, dans le cas contraire, vous pouvez dire à TypedDict de traiter chaque champ comme non requis par défaut, puis d'utiliser Required pour marquer les champs réellement requis.

    Par exemple, c'est le même que le code précédent*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from typing import TypedDict, Required
     
    # `total=False` means all fields are not required by default
    class User(TypedDict, total=False):
        name: Required[str]
        age: Required[int]
        married: bool  # now this is optional
     
    marie: User = {'name': 'Marie', 'age': 29, 'married': True}
    fredrick : User = {'name': 'Fredrick', 'age': 17}  # 'married' is not required

    contextlib.chdir

    contextlib a un petit ajout, qui est un gestionnaire de contexte appelé chdir. Tout ce qu'il fait est de remplacer le répertoire de travail actuel par le répertoire spécifié dans le gestionnaire de contexte et de le remettre à ce qu'il était avant lorsqu'il se ferme.

    Un cas d'utilisation potentiel peut être de rediriger vers où vous écrivez les journaux*:

    Code Python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import os
     
    def write_logs(logs):
        with open('output.log', 'w') as file:
            file.write(logs)
     
     
    def foo():
        print("Scanning files...")
        files = os.listdir(os.curdir)  # lists files in current directory
        logs = do_scan(files)
     
        print("Writing logs to /tmp...")
        with contextlib.chdir('/tmp'):
            write_logs(logs)
     
        print("Deleting files...")
        files = os.listdir(os.curdir)
        do_delete(files)

    De cette façon, vous n'avez pas à vous soucier de modifier et de rétablir manuellement le répertoire actuel, le gestionnaire de contexte le fera pour vous.

    Source : annonce Python 3.11 bêta

    Voir aussi :

    La prochaine version de l'interpréteur Python standard, CPython, va s'accompagner d'améliorations significatives des performances, ont annoncé les développeurs durant la PyCon
    Contribuez au club : Corrections, suggestions, critiques, ... : Contactez le service news et Rédigez des actualités

  8. #8
    Chroniqueur Actualités
    Avatar de Bruno
    Homme Profil pro
    Rédacteur technique
    Inscrit en
    mai 2019
    Messages
    917
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Rédacteur technique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : mai 2019
    Messages : 917
    Points : 10 949
    Points
    10 949
    Par défaut Python 3.11 est en moyenne 25 % plus rapide que 3.10
    Python 3.11 est en moyenne 25 % plus rapide que 3.10,
    compilé avec GCC sur Ubuntu Linux, l'accélération peut aller de 10 à 60 %

    Python 3.11 est–il vraiment le Python le plus rapide ? Une chose est sûre, CPython 3.11 est en moyenne 25 % plus rapide que CPython 3.10 lorsqu'il est mesuré avec la suite de benchmark pyperformance, et compilé avec GCC sur Ubuntu Linux. En fonction de la charge de travail, l'accélération peut atteindre 10 à 60 %. L'équipe de développement de Python a annoncé le 4 octobre les améliorations et les nouvelles fonctionnalités de la version 3.11 de Python. Dans le but d’améliorer les performances du langage de programmation Python, Microsoft a lancé Faster CPython.

    Il s’agit d’un projet financé par Microsoft, dont les membres comprennent l'inventeur de Python Guido van Rossum, l'ingénieur logiciel senior de Microsoft Eric Snow, et Mark Shannon qui est sous contrat avec Microsoft en tant que responsable technique du projet. « Python est largement reconnu comme étant lent. Alors que Python n'atteindra jamais les performances des langages de bas niveau comme C, Fortran, ou même Java, nous aimerions qu'il soit compétitif avec les implémentations rapides des langages de script, comme V8 pour Javascript », déclare Mark Shannon.

    Nom : python.png
Affichages : 69445
Taille : 3,1 Ko

    Python est un langage de programmation interprété, multi-paradigme et multi-plateformes. Il favorise la programmation impérative structurée, fonctionnelle et orientée objet. Il est doté d'un typage dynamique fort, d'une gestion automatique de la mémoire par ramasse-miettes et d'un système de gestion d'exceptions ; il est ainsi similaire à Perl, Ruby, Scheme, Smalltalk et Tcl.

    Pour être performantes, les machines virtuelles pour les langages dynamiques doivent spécialiser le code qu'elles exécutent en fonction des types et des valeurs du programme en cours d'exécution. Cette spécialisation est souvent associée aux compilateurs Just-in-time (JIT), mais elle est bénéfique même sans génération de code machine. Le projet Faster CPython se concentre sur deux domaines majeurs de Python : un démarrage et une exécution plus rapides.

    Notons que la spécialisation permet d'améliorer les performances, et l'adaptation permet à l'interprète de changer rapidement lorsque le modèle d'utilisation d'un programme change, limitant ainsi la quantité de travail supplémentaire causée par une mauvaise spécialisation.

    Démarrage plus rapide

    Python met en cache le bytecode dans le répertoire __pycache__ pour accélérer le chargement des modules. Dans la version 3.10, l'exécution des modules Python ressemblait à ceci :

    Read __pycache__ -> Unmarshal -> Heap allocated code object -> Evaluate

    Dans Python 3.11, les modules de base essentiels au démarrage de Python sont "bloqués". Cela signifie que leurs objets de code (et bytecode) sont alloués statiquement par l'interpréteur. Cela réduit les étapes du processus d'exécution des modules à ceci :

    Statically allocated code object -> Evaluate

    Le démarrage de l'interpréteur est désormais 10 à 15 % plus rapide dans Python 3.11. Cela a un impact important pour les programmes à courte durée d'exécution utilisant Python. Exécution plus rapide Les frames Python sont créés chaque fois que Python appelle une fonction Python. Cette trame contient des informations sur l'exécution. Les nouvelles optimisations des frames sont les suivantes :

    • Rationalisation du processus de création de trames ;
    • Éviter l'allocation de mémoire en réutilisant généreusement l'espace de trame sur la pile C ;
    • Rationalisation de la structure interne de la trame pour qu'elle ne contienne que les informations essentielles. Les frames contenaient auparavant des informations supplémentaires de débogage et de gestion de la mémoire.

    Les objets frame de l'ancien style ne sont maintenant créés que sur demande des débogueurs ou des fonctions d'introspection Python telles que sys._getframe ou inspect.currentframe. Pour la plupart du code utilisateur, aucun objet frame n'est créé du tout. En conséquence, presque tous les appels de fonctions Python ont été accélérés de manière significative. Nous avons mesuré une accélération de 3 à 7 % dans pyperformance.

    Lors d'un appel de fonction Python, Python appelle une fonction C évaluatrice pour interpréter le code de cette fonction. Cela limite efficacement la récursion Python pure à ce qui est fiable pour la pile C. Avec 3.11, lorsque CPython détecte un code Python appelant une autre fonction Python, il crée un nouveau frame et "saute" vers le nouveau code à l'intérieur du nouveau frame. Cela évite d'appeler la fonction d'interprétation C.

    Faster CPython explore les optimisations pour CPython. Comme dit précédemment, l'équipe principale est financée par Microsoft pour travailler sur ce projet à temps plein. Pablo Galindo Salgado est également financé par Bloomberg LP pour travailler sur le projet à temps partiel. Enfin, de nombreux contributeurs sont des bénévoles de la communauté.

    Le langage Python est placé sous une licence libre proche de la licence BSD et fonctionne sur la plupart des plateformes informatiques, des smartphones aux ordinateurs, de Windows à Unix avec notamment GNU/Linux en passant par macOS, ou encore Android, iOS, et peut aussi être traduit en Java ou .NET. Il est conçu pour optimiser la productivité des programmeurs en offrant des outils de haut niveau et une syntaxe simple à utiliser.

    La plupart des appels de fonctions Python ne consomment plus d'espace dans la pile C. Cela accélère la plupart de ces appels. Cela accélère la plupart de ces appels. Dans les fonctions récursives simples comme fibonacci ou factorielle, une accélération de 1,7x a été observée. Cela signifie également que les fonctions récursives peuvent récurer beaucoup plus profondément (si l'utilisateur augmente la limite de récursion). Nous avons mesuré une amélioration de 1 à 3 % de la performance de py.

    « L'ajout d'un interprète spécialisé et adaptatif à CPython apportera des améliorations significatives en termes de performances. Il est difficile d'avancer des chiffres significatifs, car cela dépend beaucoup des benchmarks et de travaux qui n'ont pas encore été réalisés. Des expérimentations approfondies suggèrent des accélérations allant jusqu'à 50 %. Même si le gain de vitesse n'était que de 25 %, cela resterait une amélioration intéressante », déclare Shannon.

    « Plus précisément, nous voulons atteindre ces objectifs de performance avec CPython afin d'en faire bénéficier tous les utilisateurs de Python, y compris ceux qui ne peuvent pas utiliser PyPy ou d'autres machines virtuelles alternatives », ajoute-t-il. Lorsque Devclass s'est entretenu avec Pablo Galindo, membre du conseil de direction de Python et développeur principal, au sujet du nouveau profileur de mémoire Memray, il a décrit comment l'équipe Python utilise le travail de Microsoft dans la version 3.11.

    « L'une des choses que nous faisons est que nous rendons l'interpréteur plus rapide, déclare Pablo Galindo, membre du conseil de direction de Python et développeur principal. Mais il va également utiliser un peu plus de mémoire, juste un peu, parce que la plupart de ces optimisations ont une sorte de coût en mémoire, étant donné que nous devons stocker des choses pour les utiliser plus tard, ou parce que nous avons une version optimisée mais parfois, quelqu'un a besoin de demander une version non optimisée pour le débogage, donc nous devons stocker les deux. »

    PEP 659 : spécialisation de l'interpréteur adaptatif

    Le PEP 659 est l'un des éléments clés du projet Faster CPython. L'idée générale est que, bien que Python soit un langage dynamique, la plupart du code comporte des régions où les objets et les types changent rarement. Ce concept est connu sous le nom de stabilité des types. Au moment de l'exécution, Python essaie de rechercher des modèles communs et la stabilité des types dans le code en cours d'exécution. Python remplace alors l'opération en cours par une opération plus spécialisée.

    Cette opération spécialisée utilise des chemins rapides disponibles uniquement pour ces cas d'utilisation/types, qui sont généralement plus performants que leurs équivalents génériques. Cela fait également appel à un autre concept appelé "inline caching", dans lequel Python met en cache les résultats des opérations coûteuses directement dans le bytecode. Le spécialisateur combinera également certaines paires d'instructions communes en une super-instruction. Cela réduit l'overhead pendant l'exécution.

    Python ne se spécialise que lorsqu'il voit du code "hot" (exécuté plusieurs fois). Cela évite à Python de perdre du temps pour du code "run-once". Python peut également se déspécialiser lorsque le code est trop dynamique ou lorsque l'utilisation change. La spécialisation est tentée périodiquement, et les tentatives de spécialisation ne sont pas trop coûteuses. Cela permet à la spécialisation de s'adapter aux nouvelles circonstances.

    Le projet pyperformance a pour but d'être une source faisant autorité en matière de benchmarks pour toutes les implémentations de Python. L'accent est mis sur les benchmarks du monde réel, plutôt que sur les benchmarks synthétiques, en utilisant des applications complètes lorsque cela est possible.

    Source : Python

    Et vous ?

    « Python 3.11 est en moyenne 25 % plus rapide que 3.10 », êtes-vous d'avis ?

    Que pensez-vous de Python 11 ?

    Avez-vous une expérience avec Python ?

    Êtes-vous pour ou contre la suppression du Global Interpreter Lock ?

    Voir aussi :

    Python 3.11 améliorera l'emplacement des erreurs dans les tracebacks et apporte de nouvelles fonctionnalités

    La version 3.2 du framework Django est disponible, avec la découverte automatique d'AppConfig, elle apporte de nouveaux décorateurs pour le module d'administration

    Django 2.0 est disponible en version stable, quelles sont les nouveautés dans cette version du framework Web écrit en Python ?

    JetBrains soutient Django : bénéficiez d'une remise de 30 % pour l'achat d'une licence individuelle PyCharm Professional et l'intégralité des sommes perçues seront reversées à la Fondation Django
    Contribuez au club : corrections, suggestions, critiques, ... Contactez le service news et Rédigez des actualités

Discussions similaires

  1. Réponses: 0
    Dernier message: 16/06/2021, 17h14
  2. Réponses: 0
    Dernier message: 07/10/2020, 20h29
  3. Kernel Linux : la version stable 2.6.38 est disponible
    Par Hinault Romaric dans le forum Linux
    Réponses: 0
    Dernier message: 16/03/2011, 13h10
  4. Linux : la version finale de Gentoo 2010 est disponible
    Par Katleen Erna dans le forum Actualités
    Réponses: 1
    Dernier message: 06/10/2009, 09h13
  5. Réponses: 56
    Dernier message: 03/09/2009, 01h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo