Question

Le concept de coroutine semble très intéressant, mais je ne sais pas s'il est logique dans un véritable environnement productif? Quels sont les cas d’utilisation des coroutines, qui peuvent être résolus de manière plus élégante, plus simple ou plus efficace que d’autres méthodes?

Était-ce utile?

La solution

Les véritables coroutines nécessitent l'assistance de vos outils. Elles doivent être implémentées par le compilateur et supportées par le framework sous-jacent.

Un exemple concret de Coroutines se trouve avec le "rendement renvoyé" mot-clé fourni en C # 2.0, qui vous permet d'écrire une méthode renvoyant plusieurs valeurs pour la mise en boucle.

Le "rendement" " Cependant, ses limitations ont des limites: l’implémentation utilise une classe auxiliaire pour capturer l’état et elle ne prend en charge qu’un cas spécifique de coroutine en tant que générateur (itérateur).

Dans le cas plus général, Coroutines présente l'avantage de rendre certains calculs basés sur l'état beaucoup plus faciles à exprimer et à comprendre - l'implémentation d'une machine à états sous la forme d'un ensemble de coroutines peut s'avérer plus élégante que des approches plus courantes . Mais cela nécessite un support et des outils qui n'existent pas encore en C # ou en Java.

Autres conseils

Quelques bonnes réponses décrivant ce que sont les coroutines.

Mais pour un cas d'utilisation réel. Prenez un serveur web. Il dispose de plusieurs connexions simultanées et il souhaite planifier la lecture et l'écriture de toutes.

Ceci peut être implémenté à l’aide de coroutines. Chaque connexion est une coroutine qui lit / écrit une petite quantité de données, puis "rendements". contrôle vers le planificateur, qui passe à la coroutine suivante (qui fait la même chose) lorsque nous parcourons toutes les connexions disponibles.

Beaucoup, par exemple:

grep TODO *.c *.h | wc -l

Le pipeline ci-dessus est exactement une coroutine: la commande grep génère une séquence de lignes qui vont dans un tampon, la commande wc "les mange"; si la mémoire tampon est pleine, le grep "bloque" jusqu'à ce que le tampon se vide et si le tampon est vide, la commande wc attend la nouvelle entrée.

Le problème avec les coroutines est qu’elles sont le plus souvent utilisées maintenant soit dans des modèles plus restreints, comme les générateurs Python mentionnés, ou en tant que pipelines.

Si vous souhaitez les consulter davantage, consultez les articles de Wikipédia, en particulier sur les coroutines et itérateurs .

Je sais que cela fait presque 5 ans que la question a été posée, mais je suis surpris que personne ne mentionne le cas d'utilisation de jeux où les coroutines sont beaucoup utilisées pour réduire sensiblement le temps de calcul.

Pour maintenir une cadence d'images constante dans un jeu, disons que 60 ips, vous avez environ 16,6 ms pour exécuter du code dans chaque image. Cela inclut la simulation physique, le traitement des entrées, le dessin / la peinture.

Disons que votre méthode est exécutée dans chaque image. Si votre méthode prend beaucoup de temps et finit par couvrir plusieurs images, vous allez répartir le reste du calcul dans la boucle de jeu, ce qui permettra à l'utilisateur de voir "jank". (une baisse soudaine du taux de trame).

Ce que vous permettent de faire les coroutines, c’est en quelque sorte le temps de diviser ce calcul afin qu’il soit exécuté un peu dans chaque image.

Pour cela, Coroutines permet essentiellement à la méthode de "céder" le calcul de retour à l'appelant " (dans ce cas, la boucle du jeu) de sorte que la prochaine fois que la méthode est appelée, elle reprend là où elle s’était arrêtée.

Les coroutines sont utiles pour implémenter les modèles producteur / consommateur.

Par exemple, Python a introduit des coroutines dans une fonctionnalité de langage appelée générateurs , qui était destiné à simplifier la mise en œuvre des itérateurs.

Ils peuvent également être utiles pour implémenter le multitâche coopératif, où chaque tâche est une coroutine qui cède la place à un programmateur / réacteur.

Les Coroutines peuvent être utiles chaque fois qu’un système a deux ou plusieurs morceaux de code dont la représentation la plus naturelle serait une série d’étapes séquentielles qui nécessitent beaucoup d’attente.

Par exemple, considérons un périphérique doté d’une interface utilisateur LCD-clavier, d’un modem, et devant utiliser le modem pour appeler et signaler périodiquement son état, indépendamment de ce que l’utilisateur du clavier fait. Le moyen le plus agréable d’écrire l’interface utilisateur consiste à utiliser des fonctions telles que "input_numeric_value (& CONV_SPEED_FORMAT, & conveyor_speed)"; qui reviendra quand un utilisateur aura entré une valeur, et le moyen le plus agréable de gérer la communication peut être d'utiliser des fonctions comme "wait_for_carrier ();" qui reviendra lorsque l’unité sera connectée ou déterminera que cela ne va pas.

Sans coroutines, le sous-système d'interface utilisateur ou le modem devrait être implémenté à l'aide d'une machine à états. L'utilisation de coroutines permet aux deux sous-systèmes d'être écrits dans le style le plus naturel. Notez qu’il est important qu’aucun des sous-systèmes ne dure très longtemps sans mettre les éléments dans un état "cohérent". Etat et appel de rendement (), ni les appels de rendement () sans mettre les choses dans un "cohérent" déclarez d’abord, mais il n’est généralement pas difficile de respecter ces contraintes.

Notez que bien que l'on puisse utiliser le multitâche complet, cela nécessite l'utilisation de verrous partout, à tout moment où l'état partagé est modifié. Etant donné que le commutateur de coroutine ne changera jamais de choses sauf lors d'appels à yield (), chaque routine peut modifier librement l'état partagé, à condition qu'elle s'assure que tout est en ordre avant le prochain rendement et qu'elle est prête pour que l'autre routine modifie l'état " ; pendant " le rendement ().

En tant qu'exemple plus spécifique dans la chaîne producteur / consommateur, un programme aussi simple que le programme de reporting par lots humble pourrait en réalité utiliser des co-routines.

L'indicateur de clé de cet exemple est d'avoir un travail non trivial pour consommer des données d'entrée (par exemple, l'analyse de données ou l'accumulation de charges et de paiements sur un compte), et un travail non trivial pour produire le résultat. Lorsque vous avez ces caractéristiques:

  • Il est facile d’organiser / comprendre le code côté entrée si vous pouvez " émettre " unités de travail à divers endroits.
  • Il est également facile d’organiser / comprendre le code côté sortie s’il peut "saisir" les données. la prochaine unité de travail dans une structure de contrôle imbriquée.

alors les coroutines et les files d’attente sont des techniques agréables à avoir à votre disposition.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top