Maison > Article > développement back-end > Quel artefact ! Un framework de crawler Python efficace et plus facile à utiliser que les requêtes !
Récemment, le projet back-end Python de l'entreprise a été restructuré et toute la logique back-end a été fondamentalement modifiée pour utiliser des coroutines « asynchrones ». En regardant l'écran plein de code décoré avec async wait (l'implémentation de coroutines en Python), je me suis soudain senti confus et perdu.
Bien que j'aie déjà appris ce qu'est une "coroutine", je ne l'ai pas exploré en profondeur, j'ai donc juste profité de cette occasion pour l'apprendre attentivement.
C'est parti
En termes simples, les coroutines sont basées sur des threads mais sont plus légères que les threads. Pour le noyau système, les coroutines ont des caractéristiques invisibles, c'est pourquoi ce thread léger géré par les programmeurs qui écrivent leurs propres programmes est souvent appelé « thread de l'espace utilisateur ».
1. Le contrôle du thread est entre les mains du système d'exploitation, tandis que le contrôle de la coroutine est entièrement entre les mains de l'utilisateur. Par conséquent, l'utilisation de coroutines peut réduire le changement de contexte lorsque le programme est en cours d'exécution et améliorer efficacement. l'efficacité du programme.
2. Lors de la création d'un thread, la taille de pile par défaut allouée au thread par le système est de 1 M, tandis que la coroutine est plus légère, proche de 1 K, donc plus de coroutines peuvent être ouvertes dans la même mémoire.
3. Étant donné que la nature des coroutines n'est pas multithread mais monothread, il n'est pas nécessaire d'avoir un mécanisme de verrouillage multithread. Puisqu'il n'y a qu'un seul thread, il n'y a pas de conflit causé par l'écriture simultanée de variables. Le contrôle des ressources partagées dans une coroutine ne nécessite pas de verrouillage, seul le statut doit être déterminé. Par conséquent, l'efficacité d'exécution des coroutines est bien supérieure à celle des multi-threads, et elle évite également efficacement la concurrence dans les multi-threads.
Scénarios applicables : les coroutines conviennent aux scénarios bloqués et nécessitent une grande quantité de concurrence.
Scénarios inapplicables : les coroutines ne conviennent pas aux scénarios comportant un grand nombre de calculs (car l'essence des coroutines est de basculer dans un seul thread). Si vous rencontrez cette situation, vous devez toujours utiliser d'autres moyens pour la résoudre). .
À ce stade, nous devrions avoir une compréhension générale des "coroutines", mais à ce stade de l'histoire, je crois que certains amis sont encore pleins de questions : comment les "coroutines" aident-elles test d'interface ? Ne vous inquiétez pas, la réponse est ci-dessous.
Je pense que les amis qui ont utilisé Python pour tester l'interface connaissent la bibliothèque de requêtes. La requête http implémentée dans les requêtes est une requête synchrone, mais en fait, sur la base des caractéristiques de blocage d'E/S des requêtes http, il est très approprié d'utiliser des coroutines pour implémenter des requêtes http « asynchrones » afin d'améliorer l'efficacité des tests.
Je pense que quelqu'un l'a remarqué il y a longtemps, donc après quelques explorations sur Github, comme prévu, j'ai finalement trouvé une bibliothèque open source qui prend en charge les coroutines pour appeler "de manière asynchrone" http: httpx.
httpx est une bibliothèque open source qui hérite de presque toutes les fonctionnalités des requêtes et prend en charge les requêtes http "asynchrones". Pour faire simple, httpx peut être considéré comme une version améliorée des requêtes.
Maintenant, vous pouvez me suivre pour voir la puissance de httpx.
L'installation httpx est très simple et peut être exécutée dans un environnement Python 3.6 ou supérieur.
pip install httpx
Comme le dit le proverbe, l'efficacité détermine le succès ou l'échec. J'ai utilisé les méthodes httpx asynchrones et synchrones pour comparer la consommation de temps des requêtes http par lots. Jetons un coup d'œil aux résultats ~
Tout d'abord, jetons un coup d'œil aux performances chronophages des requêtes http synchrones :
import asyncio import httpx import threading import time def sync_main(url, sign): response = httpx.get(url).status_code print(f'sync_main: {threading.current_thread()}: {sign}2 + 1{response}') sync_start = time.time() [sync_main(url='http://www.baidu.com', sign=i) for i in range(200)] sync_end = time.time() print(sync_end - sync_start)
Le code est. relativement simple, vous pouvez voir Dans sync_main, l'accès http synchrone à Baidu a été implémenté 200 fois.
Le résultat après exécution est le suivant (une partie de la sortie clé est interceptée...) :
sync_main: <_MainThread(MainThread, started 4471512512)>: 192: 200 sync_main: <_MainThread(MainThread, started 4471512512)>: 193: 200 sync_main: <_MainThread(MainThread, started 4471512512)>: 194: 200 sync_main: <_MainThread(MainThread, started 4471512512)>: 195: 200 sync_main: <_MainThread(MainThread, started 4471512512)>: 196: 200 sync_main: <_MainThread(MainThread, started 4471512512)>: 197: 200 sync_main: <_MainThread(MainThread, started 4471512512)>: 198: 200 sync_main: <_MainThread(MainThread, started 4471512512)>: 199: 200 16.56578803062439
Vous pouvez voir que dans la sortie ci-dessus, le thread principal n'est pas commuté (car il s'agit d'un seul thread !) Le les requêtes sont exécutées dans l’ordre (car il s’agit d’une requête synchrone).
Le programme a pris un total de 16,6 secondes à exécuter.
Essayons la requête http "asynchrone" ci-dessous :
import asyncio import httpx import threading import time client = httpx.AsyncClient() async def async_main(url, sign): response = await client.get(url) status_code = response.status_code print(f'async_main: {threading.current_thread()}: {sign}:{status_code}') loop = asyncio.get_event_loop() tasks = [async_main(url='http://www.baidu.com', sign=i) for i in range(200)] async_start = time.time() loop.run_until_complete(asyncio.wait(tasks)) async_end = time.time() loop.close() print(async_end - async_start)
Le code ci-dessus utilise le mot-clé async wait dans async_main pour implémenter le http "asynchrone", via asyncio (la bibliothèque io asynchrone demande la page d'accueil de Baidu 200 fois et imprime l'heure consommation) .
Après avoir exécuté le code, vous pouvez voir le résultat suivant (une partie de la sortie clé a été interceptée...).
async_main: <_MainThread(MainThread, started 4471512512)>: 56: 200 async_main: <_MainThread(MainThread, started 4471512512)>: 99: 200 async_main: <_MainThread(MainThread, started 4471512512)>: 67: 200 async_main: <_MainThread(MainThread, started 4471512512)>: 93: 200 async_main: <_MainThread(MainThread, started 4471512512)>: 125: 200 async_main: <_MainThread(MainThread, started 4471512512)>: 193: 200 async_main: <_MainThread(MainThread, started 4471512512)>: 100: 200 4.518340110778809
Vous pouvez voir que bien que l'ordre soit foiré (56, 99, 67...) (c'est parce que le programme continue de basculer entre les coroutines), le thread principal ne change pas (les coroutines sont toujours de nature monothread ).
Le processus prend 4,5 secondes au total.
Par rapport aux 16,6 secondes que prend la requête synchrone, elle est raccourcie de près de 73% !
Comme le dit le proverbe, un pas est rapide et chaque pas est rapide. En termes de consommation de temps, le httpx « asynchrone » est en effet bien plus rapide que le http synchrone. Bien sûr, les « coroutines » peuvent non seulement permettre de tester l'interface en termes d'efficacité des requêtes.Après avoir maîtrisé les « coroutines », je pense que le niveau technique des amis peut également être amélioré à un niveau supérieur, concevant ainsi un meilleur cadre de test.
D'accord, c'est tout le contenu partagé aujourd'hui, si vous l'aimez, n'hésitez pas à l'aimer~
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!