J'ai eu du mal à comprendre comment et pourquoi la fonctionnalité asynchrone fonctionne en python et je ne suis toujours pas sûr de tout comprendre correctement (en particulier la partie "pourquoi"). S'il vous plait corrigez moi si je me trompe.
Le but des méthodes async et des threads est de permettre le traitement simultané de plusieurs tâches.
L'approche des threads semble simple et intuitive. Si le programme python traite plusieurs tâches simultanément, nous avons un thread (avec des sous-threads) pour chaque tâche, la pile de chaque thread reflète l'étape actuelle du traitement de la tâche correspondante. Tout est simple, il existe des mécanismes faciles à utiliser pour démarrer un nouveau fil et attendre les résultats.
Si je comprends bien, le seul problème avec cette approche est que les threads sont chers.
Une autre approche consiste à utiliser des variables async
. Je peux voir plusieurs inconvénients avec cette approche. Je n'en nommerai que deux. Nous avons maintenant deux types de méthodes: les méthodes habituelles et les méthodes async
. Dans 90% des cas, la seule différence est que vous devez vous rappeler que cette méthode est async
et n'oubliez pas d'utiliser le mot clé await
lorsque vous appelez cette méthode. Et oui, vous ne pouvez pas appeler la méthode async
à partir de méthodes normales. Et tout ce async
- await
garbage syntaxique tout autour du programme est seulement pour indiquer que cette méthode est capable de donner le contrôle à la boucle de message.
L'approche des fils est libre de tous ces inconvénients. Mais l'approche async
- await
permet de traiter beaucoup plus de tâches simultanées que l'approche threads. Comment est-ce possible?
Pour chaque tâche simultanée, nous avons toujours une pile d’appels, mais c’est maintenant une pile d’appels coroutine. Je ne suis pas tout à fait sûr, mais il semble que ce soit la principale différence: les piles habituelles sont des piles de système d'exploitation, elles sont chères, les piles de coroutine ne sont qu'une structure en python, elles sont beaucoup moins chères. Est-ce que ma compréhension est correcte?
Si cela est correct, ne serait-il pas préférable de découpler les threads/piles d'appels python des threads/piles d'appels du système d'exploitation pour réduire les coûts des threads python?
Désolé si cette question est stupide. Je suis certain que l’approche async
-await
a été choisie pour plusieurs raisons. Je veux juste comprendre ces raisons.
Mettre à jour:
Pour ceux qui ne pensent pas que cette question n'est pas bonne et trop large.
Voici un article Unyielding - qui commence par des explications sur la raison pour laquelle les discussions sont mauvaises et qui annonce une approche async
. Thèse principale: les threads sont diaboliques, il est trop difficile de raisonner sur une routine pouvant être exécutée simultanément à partir d'un nombre arbitraire de threads.
Merci à Nathaniel J. Smith (auteur de python Trio library) qui a suggéré ce lien.
À propos, les arguments de l'article ne me convainquent pas, mais peuvent quand même être utiles.
Cet article répond à vos questions.
TL; DR?
Les threads en Python sont inefficaces en raison de GIL (verrou d'interprète global), ce qui signifie que plusieurs threads ne peuvent pas être exécutés en parallèle, contrairement à ce que l'on attend d'un système multiprocesseur. De plus, vous devez compter sur l'interprète pour passer d'un thread à l'autre, ce qui ajoute à l'inefficacité.
asyc/ asyncio autorise la concurrence au sein d'un seul thread. Cela vous donne, en tant que développeur, un contrôle beaucoup plus fin du basculement des tâches et peut offrir de bien meilleures performances pour les tâches liées aux E/S simultanées que le threading Python.
La 3ème approche que vous ne mentionnez pas est multitraitement . Cette approche utilise des processus de simultanéité et permet aux programmes d’utiliser pleinement le matériel à plusieurs cœurs.
Asyncio est un monde totalement différent et, autant que je sache, c’est la réponse de python à node.js qui fait cela depuis le début. Par exemple. ce document officiel en python à propos de asyncio déclare:
La programmation asynchrone est différente de la programmation "séquentielle" classique
Donc, vous devez décider si vous voulez sauter dans ce trou de lapin et apprendre cette terminologie. Cela n'a probablement de sens que si vous êtes confronté à des tâches lourdes liées au réseau ou au disque. Si vous êtes, par exemple, Cet article affirme que l'asyncio de python 3 pourrait être plus rapide que node.js et proche des performances de Go.
Cela dit: je n’ai pas encore utilisé l’asyncio, je ne peux donc rien dire à ce sujet, mais je peux commenter quelques phrases de votre question:
Et tout cela de manière asynchrone - attendre des ordures syntaxiques tout autour du programme n’est que pour indiquer que cette méthode est capable de donner le contrôle à la boucle de message
Autant que je sache, vous avez une configuration initiale d'asyncio, mais tous les appels ont moins de syntaxe que de faire la même chose avec les threads dont vous avez besoin pour start()
et join()
et probablement aussi pour vérifier avec is_alive()
, et pour aller chercher le renvoyez la valeur dont vous avez besoin pour configurer un objet partagé en premier. Donc: non, asyncio a juste un aspect différent, mais à la fin, le programme aura probablement l'air plus propre qu'avec les threads.
Si je comprends bien, le seul problème avec cette approche est que les threads sont chers
Pas vraiment. Démarrer un nouveau thread est très bon marché et, autant que je sache, commencer à créer un "thread natif" en C ou en Java
la différence principale semble être la suivante: les piles habituelles sont des piles de système d’exploitation, elles sont chères, les piles de coroutine ne sont qu’une structure python, elles sont beaucoup moins chères. Est-ce que ma compréhension est correcte?
Pas vraiment. Rien ne vaut la création de threads au niveau du système d'exploitation, ils sont bon marché. Ce que l'asyncio est meilleur, c'est que vous avez besoin de moins de commutateurs de thread. Donc, si vous avez plusieurs threads simultanés en attente de réseau ou de disque, asyncio accélérera probablement les choses.