Maison > Article > développement back-end > A quoi servent les coroutines et la concurrence en python ?
Ce chapitre vous présentera le rôle des coroutines et de la concurrence en python, afin que vous puissiez comprendre les avantages et les inconvénients de l'utilisation des coroutines, ainsi que le rôle du framework de concurrence gevent. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.
Coroutine
Coroutine est un thread léger en mode utilisateur, également appelé micro-thread.
La coroutine a son propre contexte de registre et sa propre pile. Lorsque le planning est changé, le contexte de registre et la pile sont enregistrés ailleurs. Lors du retour en arrière, le contexte de registre et la pile précédemment enregistrés sont restaurés. Par conséquent : la coroutine peut conserver l'état du dernier appel (c'est-à-dire une combinaison spécifique de tous les états locaux). Chaque fois que le processus rentre, cela équivaut à entrer dans l'état du dernier appel. l'état où il est parti la dernière fois. L'emplacement du flux logique.
Avantages :
Aucune surcharge liée au changement de contexte de thread
Aucune surcharge liée au verrouillage et à la synchronisation des opérations atomiques
Commutez facilement le flux de contrôle et simplifiez le modèle de programmation
Concurrence élevée + évolutivité élevée + faible coût : ce n'est pas un problème pour un processeur de prendre en charge des dizaines de milliers de coroutines. Il est donc très approprié pour le traitement à haute concurrence.
L'opération dite atomique fait référence à une opération qui ne sera pas interrompue par le mécanisme de planification des threads une fois cette opération lancée, elle s'exécutera jusqu'à la fin sans aucun changement de contexte (switch sur un autre fil).
Les opérations atomiques peuvent être une ou plusieurs étapes, mais l'ordre ne peut pas être perturbé ou seule la partie exécutée peut être coupée. Voir dans son ensemble est au cœur de l’atomicité.
Inconvénients :
Impossible d'utiliser des ressources multicœurs : l'essence de la coroutine est un seul thread. Elle ne peut pas utiliser plusieurs cœurs d'un seul processeur en même temps. La coroutine doit être Les processus doivent coopérer pour fonctionner sur plusieurs processeurs. Bien entendu, la plupart des applications que nous écrivons quotidiennement n'ont pas cette nécessité, à moins qu'il ne s'agisse d'applications gourmandes en ressources processeur.
Les opérations de blocage (telles que les IO) bloqueront l'ensemble du programme
Utiliser Gevent
gevent est un framework de concurrence python, avec un micro-thread greenlet comme noyau, utilisant le mécanisme d'écoute des événements epoll et de nombreuses autres optimisations pour le rendre efficace. :
Exemple simple
Le sommeil de gevent peut céder le contrôle. Lorsque nous utilisons gevent dans des fonctions restreintes par le réseau ou les E/S, ces fonctions seront planifiées de manière coopérative. déchaîné. Gevent gère tous les détails pour garantir que votre bibliothèque réseau transmettra implicitement les droits d'exécution au contexte greenlet lorsque cela est possible.
import gevent def foo(): print('running in foo') gevent.sleep(0) print('com back from bar in to foo') def bar(): print('running in bar') gevent.sleep(0) print('com back from foo in to bar') # 创建线程并行执行程序 gevent.joinall([ gevent.spawn(foo), gevent.spawn(bar), ])
Résultat de l'exécution :
Synchrone et asynchrone
import random import gevent def task(pid): gevent.sleep(random.randint(0, 2) * 0.001) print('Task %s done' % pid) def synchronous(): for i in range(1, 10): task(i) def asynchronous(): threads = [gevent.spawn(task, i) for i in range(10)] gevent.joinall(threads) print('Synchronous:') synchronous() print('Asynchronous:') asynchronous()
Résultat d'exécution :
Utilisation de coroutine dans une méthode de sous-classe
peut être sous-classée Transform la classe Greenlet et surcharger sa méthode _run, similaire aux modules multi-thread et multi-processus
import gevent from gevent import Greenlet class Test(Greenlet): def __init__(self, message, n): Greenlet.__init__(self) self.message = message self.n = n def _run(self): print(self.message, 'start') gevent.sleep(self.n) print(self.message, 'end') tests = [ Test("hello", 3), Test("world", 2), ] for test in tests: test.start() # 启动 for test in tests: test.join() # 等待执行结束
Utiliser Monkey Patch pour modifier la bibliothèque standard du système (changer automatiquement de coroutines)
Lorsqu'un greenlet rencontre une opération IO, telle que l'accès au réseau, il basculera automatiquement vers d'autres greenlets, attendra que l'opération IO soit terminée, puis reviendra pour continuer l'exécution au moment approprié. temps.
Étant donné que les opérations d'E/S prennent beaucoup de temps, le programme est souvent laissé dans un état d'attente. Avec gevent changeant automatiquement de coroutines pour nous, il est garanti que les greenlets sont toujours en cours d'exécution au lieu d'attendre les IO.
Étant donné que la commutation est automatiquement effectuée lors des opérations d'E/S, gevent doit modifier certaines des bibliothèques standard fournies avec Python. Ce processus est effectué via Monkey Patch au démarrage
import gevent import requests from gevent import monkey monkey.patch_socket() def task(url): r = requests.get(url) print('%s bytes received from %s' % (len(r.text), url)) gevent.joinall([ gevent.spawn(task, 'https://www.baidu.com/'), gevent.spawn(task, 'https://www.qq.com/'), gevent.spawn(task, 'https://www.jd.com/'), ])
Sortie d'exécution :
On peut voir que les trois opérations réseau sont exécutées simultanément et que l'ordre de fin est différent
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!