web-dev-qa-db-fra.com

Qu'est-ce qu'une coroutine?

Qu'est-ce qu'une coroutine? Comment sont-ils liés à la concurrence?

174
yesraaj

Les coroutines et la concurrence sont en grande partie orthogonales. Les coroutines sont une structure de contrôle générale dans laquelle le contrôle de flux est passé en coopération entre deux routines différentes sans retour.

L'instruction 'yield' in Python en est un bon exemple. Elle crée une coroutine. Lorsque le 'rendement' est rencontré, l'état actuel de la fonction est enregistré et le contrôle est rendu à la fonction appelante. La fonction appelante peut alors renvoyer l’exécution vers la fonction exécutable et son état sera restauré au point où le "rendement" a été rencontré et l’exécution se poursuivra.

122
user21714

De programmation en Lua , section "Coroutines":

Un coroutine est similaire à un thread (au sens de multithreading): c'est une ligne d'exécution, avec sa propre pile, ses propres variables locales et son propre pointeur d'instruction; mais il partage des variables globales et la plupart du temps avec d’autres coroutines. La principale différence entre les threads et les coroutines réside dans le fait que, conceptuellement (ou littéralement, dans une machine multiprocesseur), un programme avec des threads exécute plusieurs threads en parallèle. Les routines, en revanche, sont collaboratives: à un moment donné, un programme avec routines n’exécute qu’une de ses routines et cette routine ne suspend son exécution que s’il demande explicitement à être suspendu.

Donc, le point est: Les Coroutines sont "collaboratives". Même dans un système multicœur, il n’existe qu’une seule coroutine à la fois (mais plusieurs threads peuvent être exécutés en parallèle). Il n'y a pas de préemption entre les coroutines, la coroutine en cours d'exécution doit abandonner explicitement l'exécution.

Pour "concurrency", vous pouvez vous référer à Rob Pike slide :

La simultanéité est la composition de calculs exécutés indépendamment.

Ainsi, lors de l'exécution de la coroutine A, il passe le contrôle à la coroutine B. Ensuite, au bout d'un certain temps, la coroutine B rend le contrôle à la coroutine A. Puisqu'il existe une dépendance entre les coroutines, et ils doivent fonctionner en tandem, les deux coroutines ne sont donc pas pas de simultanéité .

67
Nan Xiao

Je trouve la plupart des réponses trop techniques, même s’il s’agit d’une question technique. J'ai eu du mal à comprendre le processus coroutine. Je le reçois un peu mais ensuite je ne le reçois pas en même temps.

J'ai trouvé cette réponse très utile ici:

https://dev.to/thibmaek/explain-coroutines-like-im-five-2d9

Pour citer Idan Arye:

Pour construire votre histoire, je la mettrais à peu près comme ceci:

Vous commencez à regarder le dessin, mais c'est l'intro. Au lieu de regarder l'intro, vous basculez vers le jeu et entrez dans le lobby en ligne - mais il faut 3 joueurs et seuls vous et votre sœur y êtes. Au lieu d'attendre qu'un autre joueur vous rejoigne, passez à vos devoirs et répondez à la première question. La deuxième question contient un lien vers une vidéo YouTube que vous devez regarder. Vous l'ouvrez - et le chargement commence. Au lieu d'attendre son chargement, vous revenez au dessin animé. L'intro est terminée, alors vous pouvez regarder. Maintenant, il y a des publicités - mais entre temps, un troisième joueur a rejoint le groupe et vous passez au jeu. Et ainsi de suite ...

L'idée est que vous ne changez pas simplement les tâches très rapidement pour donner l'impression que vous faites tout en même temps. Vous utilisez le temps que vous attendez pour que quelque chose se passe (IO) pour faire d'autres choses qui nécessitent votre attention directe.

Vérifiez le lien, il y a beaucoup plus que je ne peux pas tout citer.

26
mr1031011

Coroutine est similaire à subroutine/threads. La différence est qu'une fois qu'un appelant a appelé un sous-programme/threads, il ne reviendra jamais à la fonction appelant. Mais un coroutine peut revenir à l'appelant après avoir exécuté un morceau de code lui permettant d'exécuter une partie de son propre code et de revenir au point où il a cessé l'exécution et de continuer à partir de là. c'est à dire. Une coroutine a plus d'un point d'entrée et de sortie

11
Twinkle
  • Les coroutines sont d'excellentes fonctionnalités disponibles dans la langue Kotlin
  • Les Coroutines sont une nouvelle façon d'écrire du code asynchrone, non bloquant (et bien plus encore)
  • Les coroutines sont des fils légers. Un thread léger signifie qu’il n’est pas mappé sur un thread natif. Il n’est donc pas nécessaire de changer de contexte sur le processeur, ils sont donc plus rapides.
  • il ne mappe pas sur le thread natif
  • Coroutines et les threads sont multitâches. Mais la différence est que les threads sont gérés par le système d'exploitation et les coroutines par les utilisateurs.

Fondamentalement, il existe deux types de Coroutines:

  1. Sans pile
  2. Empilable

Kotlin implémente des coroutines sans pile - cela signifie que les coroutines n’ont pas de pile, donc elles ne sont pas mappées sur un thread natif.

Voici les fonctions pour démarrer la coroutine:

launch{}

async{}

Vous pouvez en apprendre plus d'ici:

https://www.kotlindevelopment.com/deep-dive-coroutines/

https://blog.mindorks.com/what-are-coroutines-in-kotlin-bf4fecd476e9

9
Dhaval Jivani

Sur une note différente, dans python gevent la bibliothèque est une bibliothèque réseau basée sur coroutine qui vous donne des fonctionnalités filiformes telles que des requêtes réseau asynchrones, sans la surcharge de créer et La bibliothèque coroutine utilisée est greenlet.

4
joseph

De Python Coroutine :

L'exécution de coroutines Python peut être suspendue et reprise à plusieurs endroits (voir coroutine). Dans le corps d'une fonction de coroutine, les identifiants wait et async deviennent des mots clés réservés. ne peut être utilisé que dans les corps de fonction de coroutine.

De Coroutines (C++ 20)

Une coroutine est une fonction qui peut suspendre l'exécution pour qu'elle soit reprise plus tard . Les Coroutines sont sans pile: elles suspendent l'exécution en retournant à l'appelant. Cela permet un code séquentiel qui s'exécute de manière asynchrone (par exemple, pour gérer des E/S non bloquantes sans rappels explicites), et prend également en charge des algorithmes sur des séquences infinies calculées différemment et d'autres utilisations.

Comparez avec la réponse d'un autre:

À mon avis, la partie reprise plus tard est une différence fondamentale, tout comme @ Twinkle's.
Bien que de nombreux champs du document soient toujours en cours, cette partie est semblable à la plupart des réponses, sauf celle de @Nan Xiao.

Les routines, en revanche, sont collaboratives: à un moment donné, un programme avec routines n’exécute qu’une de ses routines et cette routine ne suspend son exécution que s’il demande explicitement à être suspendu.

Comme il est cité dans Program in Lua, c'est peut-être lié à la langue (pas familier avec Lua actuellement), tous les documents ne mentionnent pas la seulement une partie .

La relation avec concurrent:
Il existe une partie "Exécution" de Coroutines (C++ 20) . Trop long pour être cité ici.
Outre le détail, il existe plusieurs états.

When a coroutine begins execution  
When a coroutine reaches a suspension point  
When a coroutine reaches the co_return statement  
If the coroutine ends with an uncaught exception  
When the coroutine state is destroyed either because it terminated via co_return or uncaught exception, or because it was destroyed via its handle 

comme le commentaire de @Adam Arold sous la réponse de @ user217714. C'est la concurrence.
Mais c'est différent du multithreading. de std :: thread

Les threads permettent à plusieurs fonctions de s'exécuter simultanément. Les threads commencent leur exécution immédiatement après la construction de l'objet thread associé (en attente des retards de planification du système d'exploitation), en commençant par la fonction de niveau supérieur fournie en tant qu'argument de constructeur. La valeur de retour de la fonction de niveau supérieur est ignorée et si elle se termine par une exception, std :: terminate est appelé. La fonction de niveau supérieur peut communiquer sa valeur de retour ou une exception à l'appelant via std :: promise ou en modifiant des variables partagées (pouvant nécessiter une synchronisation, voir std :: mutex et std :: atomic).

Comme il s'agit d'une concurrence d'accès, cela fonctionne comme le multithreading, en particulier lorsque l'attente est inévitable (du point de vue du système d'exploitation), c'est aussi pourquoi il est déroutant.

1
Shihe Zhang