Je n'ai utilisé Python que comme extension de scripts shell, mais récemment je l'ai utilisé pour une utilisation un peu plus décente. Puis, en tant que passionné de basse couche, je me demandais comment Python était exécuté. Alors je l'ai ramassé et je l'ai mangé.
L'histoire selon laquelle la spécification et l'implémentation du langage sont des choses différentes.
Il n'y a qu'un seul langage, Python, mais il existe plusieurs façons d'obtenir les fonctionnalités de ce langage. CPython et PyPy sont les noms de l'implémentation du langage Python. En parlant de langage C, il semble que GCC ou Clang puisse être sélectionné comme compilateur. Pour les types d'implémentations Python, voir Python Wikipedia. Il y en a beaucoup.
Ainsi, parmi diverses implémentations, CPython est l'implémentation dite de référence, qui est implémentée par l'auteur original de Python, et l'environnement d'exécution Python dans le monde est à peu près celui-ci, qui est exactement la position d'origine.
Comme vous pouvez l'imaginer d'après son nom, CPython est implémenté en langage C et PyPy est implémenté en Python. Et PyPy est plus rapide que CPython. Hmm? Qu'est-ce que cela signifie que PyPy est plus rapide que CPython lorsque C est plus rapide que Python? Je voudrais expliquer un peu à ce sujet.
Si vous lisez CPython Wikipedia,
CPython est un interpréteur de bytecode.
une. Hmm, interpréteur de code d'octet. Qu'Est-ce que c'est?
Un code d'octet est une expression intermédiaire. En d'autres termes, dans l'environnement CPython, Python est d'abord converti en bytecode, et le bytecode est exécuté par la machine virtuelle (VM). Il est appelé un interpréteur de code d'octet car il interprète et exécute les codes d'octet de manière séquentielle.
La raison de faire cela semble être que c'est plus rapide, mais je ne suis pas sûr de savoir pourquoi le temps d'exécution total est nettement plus rapide avec le code d'octet dans le langage exécuté sur l'interpréteur. Il n'y en avait pas. Cependant, au moins l'implémentation de l'interpréteur sera rafraîchissante, et si le code d'octet est laissé en cache, la plupart des traitements tels que l'analyse syntaxique ne seront pas effectués à partir de la deuxième fois, et cela semble certainement logique. Lorsque vous exécutez du code Python, des fichiers .pyc et des répertoires \ _ \ _ pycache \ _ \ _ sont créés, mais il semble que des codes d'octets y soient enregistrés. Il semble possible de prendre uniquement ces codes d'octets dans un autre environnement et de les exécuter.
cette? À propos, il existe un langage célèbre avec de telles spécifications. Oui, Java. Au début de la description Java, il y a une description que le code Java est converti en code d'octet et que Jave VM l'exécute. En Python et Java, le code source est converti (compilé) en code octet, puis la VM (interpréteur) l'exécute. Java est reconnu comme un langage de compilation et Python comme un langage d'interprétation, mais la réalité est que la compilation se fait explicitement ou implicitement.
Pourquoi PyPy est-il écrit en Python plus rapidement que CPython? Ceci est dû au fait que la compilation JIT (Just In Time) est effectuée.
Qu'est-ce que la compilation JIT? En gros, lorsque vous l'exécutez, il sera compilé dans un langage machine puis exécuté, donc ce sera plus rapide. Par exemple, considérez le traitement en boucle et les fonctions qui sont appelées plusieurs fois. S'il s'agit d'un interpréteur simple, la grammaire sera interprétée à chaque fois que ces codes sont appelés, et l'interpréteur exécutera le traitement en fonction du contenu. Puisque l'état réel de l'interpréteur est naturellement une collection de mots machine, après tout, c'est comme exécuter le langage machine après avoir exécuté le code ⇒ conversion en langage machine à chaque fois. Ensuite, si le code appelé à plusieurs reprises est converti ensemble en langage machine et que le langage machine est exécuté directement lorsque le même code est appelé, il semble que le temps de traitement de la conversion puisse être réduit. De plus, un interpréteur qui convertit le code ligne par ligne ne peut pas être optimisé en fonction du flux de traitement, mais si le code est lu et converti dans une certaine mesure dans un lot, une certaine optimisation peut être possible. ..
Cependant, il existe différentes méthodes pour accélérer la compilation JIT, et honnêtement, je ne comprends pas quelle est la clé pour accélérer. De plus, PyPy semble utiliser une méthode spéciale de compilation JIT du code de traitement, et il semble difficile d'en comprendre le contenu.
En passant, si vous regardez la page de téléchargement de PyPy, il est indiqué que le compilateur JIT ne fonctionne que sur les processeurs Intel.
These binaries include a Just-in-Time compiler. They only work on x86 CPUs that have the SSE2 instruction set (most of them do, nowadays), or on x86-64 CPUs. They also contain stackless extensions, like greenlets.
Je suppose parce que je n'ai pas vérifié la source, mais la compilation JIT signifie qu'il existe un processus dans le système de traitement du langage qui génère un assemblage qui dépend de l'architecture du processeur. La mise en œuvre d'un traitement qui correspond à de nombreuses architectures de CPU dans le monde est une tâche difficile à imaginer. Il ne peut être implémenté que pour les processeurs Intel avec un grand nombre d'utilisateurs.
Si vous utilisez PyPy, lorsque vous exécutez du code Python, PyPy le lit et l'exécute. Alors, qui exécute PyPy écrit en Python? Apparemment, le code Python de PyPy a été converti en C et compilé en binaire est en cours d'exécution.
J'ai trouvé que PyPy a un compilateur JIT intégré et est rapide, mais au fait, Python avait une bibliothèque appelée Numba qui compile JIT. En regardant le Guide Numba, il semble qu'il supporte un nombre raisonnable d'architectures CPU.
Architecture: x86, x86_64, ppc64le. Experimental on armv7l, armv8l (aarch64).
Numba travaille-t-il dur pour implémenter le support par architecture?
Après quelques recherches, Numba semble utiliser LLVM. Si vous utilisez LLVM, si vous convertissez le code Python en LLVM IR (une expression intermédiaire de LLVM), la LLVM gérera chaque architecture CPU, il n'est donc pas nécessaire de la prendre en charge du côté Numba.
J'ai essayé de savoir comment le code Python est exécuté à volonté. J'ai senti qu'il n'y avait presque aucune frontière entre le langage d'interprétation et le langage de compilation. Il compile dans le langage d'interprétation pour la vitesse, et certains langages de compilation fonctionnent comme un interprète pour plus de commodité. Je pensais connaître la compilation JIT, mais je ne connaissais pas du tout les détails.
Comment le système de traitement Python est-il implémenté et comment fonctionne-t-il? Python est-il interprété un par un ou est-il compilé?
Recommended Posts