Was ist eine Coroutine?


203

Was ist eine Coroutine? Wie hängen sie mit der Parallelität zusammen?


2
Gleichzeitiger Code muss nicht unbedingt "parallel" ausgeführt werden (lassen Sie uns keine neuen Begriffe einführen).
lucid_dreamer

2
Ich habe eine Coroutine-Bibliothek mit Standard C geschrieben, die GUI-Nachrichten für select / poll / eplll / kqueue / iocp / Win für Linux, BSD und Windows unterstützt. Es ist ein Open-Source-Projekt in github.com/acl-dev/libfiber . Ratschläge sind willkommen.
ShuXin Zheng

Weitere interessante Informationen hier: stackoverflow.com/q/16951904/14357
Spender

Ich kann mir vorstellen, dass diese Frage abgelehnt wird, wenn sie in dieser aktuellen Ära gestellt wird. Sie sind sich nicht sicher, warum es einen so großen Unterschied in der Wahrnehmung der Gemeinschaft im Vergleich zu früher gibt?
tnkh

Eine Coroutine ist eine Funktion, die ihre Ausführung vor Erreichen der Rückkehr unterbrechen und indirekt für einige Zeit die Kontrolle an eine andere Coroutine übergeben kann.
Hassanzadeh.sd

Antworten:


138

Coroutinen und Parallelität sind weitgehend orthogonal. Coroutinen sind eine allgemeine Kontrollstruktur, bei der die Flusskontrolle kooperativ zwischen zwei verschiedenen Routinen übertragen wird, ohne zurückzukehren.

Die 'Yield'-Anweisung in Python ist ein gutes Beispiel. Es entsteht eine Coroutine. Wenn die 'Ausbeute' angetroffen wird, wird der aktuelle Status der Funktion gespeichert und die Steuerung an die aufrufende Funktion zurückgegeben. Die aufrufende Funktion kann dann die Ausführung zurück an die Yielding-Funktion übertragen, und ihr Status wird bis zu dem Punkt wiederhergestellt, an dem die 'Yield' festgestellt wurde, und die Ausführung wird fortgesetzt.


19
Was ist der Unterschied zwischen dem direkten Aufrufen einer Funktion und dem Ergeben einer Coroutine, wenn diese Funktion in diese Coroutine eingeschlossen wird?
Ming Li

3
Es könnte besser sein zu erklären, dass diese beiden Konzepte in diesem Zusammenhang dann nicht wirklich „orthogonal“ sind. Sie können definitiv zeichnen, wie ähnlich die beiden Konzepte einander sind. Die Idee, die Kontrolle zwischen zwei oder mehr Dingen zu übertragen, ist sehr ähnlich.
Steviejay

8
Coroutines are a general control structure whereby flow control is cooperatively passed between two different routines without returning.<- Dies ist Parallelität. Das Wort, das Sie suchen, ist Parallelität.
Adam Arold

@steviejay orthogonal = Not similar to each other?
Tonix

1
@tonix Mir wurde gesagt, das orthogonalbedeutet "unabhängig voneinander".
Rick

77

Aus der Programmierung in Lua , CoroutinesAbschnitt " ":

Eine Coroutine ähnelt einem Thread (im Sinne von Multithreading): Es handelt sich um eine Ausführungszeile mit einem eigenen Stapel, eigenen lokalen Variablen und einem eigenen Befehlszeiger. Aber es teilt globale Variablen und meistens alles andere mit anderen Coroutinen. Der Hauptunterschied zwischen Threads und Coroutinen besteht darin, dass ein Programm mit Threads konzeptionell (oder wörtlich in einer Multiprozessor-Maschine) mehrere Threads parallel ausführt. Coroutinen hingegen sind kollaborativ: Zu einem bestimmten Zeitpunkt führt ein Programm mit Coroutinen nur eine seiner Coroutinen aus, und diese ausgeführte Coroutine setzt ihre Ausführung nur dann aus, wenn sie ausdrücklich die Suspendierung anfordert.

Der Punkt ist also: Coroutinen sind "kollaborativ". Selbst in Mehrkernsystemen wird immer nur eine Coroutine ausgeführt (es können jedoch mehrere Threads parallel ausgeführt werden). Zwischen Coroutinen besteht kein Präemptiv, die laufende Coroutine muss die Ausführung explizit aufgeben.

Für " concurrency" können Sie auf Rob Pikes Folie verweisen :

Parallelität ist die Zusammensetzung der unabhängig ausgeführten Berechnungen.

Während der Ausführung von Coroutine A wird die Kontrolle an Coroutine B übergeben. Nach einiger Zeit gibt die Coroutine B die Kontrolle an Coroutine A zurück. Da zwischen Coroutinen eine Abhängigkeit besteht und sie zusammen ausgeführt werden müssen, sind die beiden Coroutinen nicht gleichzeitig .


6
Coroutinen werden nicht unabhängig ausgeführt. Sie wechseln sich ab und warten darauf, dass der andere einen Teil der Arbeit erledigt. Sie koordinieren aktiv miteinander. Das ist das Gegenteil von Rob Pikes Definition von Parallelität.
Erick G. Hagstrom

2
@ ErickG.Hagstrom: Obwohl sie nicht unabhängig ausgeführt werden, kann die Logik jeder Coroutine unabhängig sein, oder? Wenn es richtig ist, ist es wie ein nicht präemptives Betriebssystem, das auf einer Ein-Kern-CPU ausgeführt wird. Ein Prozess muss die CPU freigeben, damit andere Aufgaben ausgeführt werden können.
Nan Xiao

6
Es gibt einen Unterschied zwischen dem Verzicht auf die CPU, um eine andere Aufgabe ausführen zu lassen, und dem Teilen eines bestimmten anderen Prozesses, dass es Zeit für die Ausführung ist. Coroutinen machen Letzteres. Das ist in keiner Weise unabhängig.
Erick G. Hagstrom

7
@ ChrisClark Ich stimme dir zu. Coroutinen sind Parallelität. Hier ist ein Zitat aus Wikipedia: Coroutinen sind Threads sehr ähnlich. Coroutinen werden jedoch kooperativ als Multitasking ausgeführt, während Threads normalerweise präventiv als Multitasking ausgeführt werden. Dies bedeutet, dass sie Parallelität, aber keine Parallelität bieten .
Smwikipedia

3
Und: Kooperatives Multitasking, auch als nicht präemptives Multitasking bezeichnet, ist eine Art von Computer-Multitasking, bei dem das Betriebssystem niemals einen Kontextwechsel von einem laufenden Prozess zu einem anderen Prozess initiiert. Stattdessen liefern Prozesse freiwillig regelmäßig oder im Leerlauf oder logisch blockiert die Kontrolle, damit mehrere Anwendungen gleichzeitig ausgeführt werden können.
Smwikipedia

47

Ich finde die meisten Antworten zu technisch, obwohl es sich um eine technische Frage handelt. Es fiel mir schwer, den Coroutine-Prozess zu verstehen. Ich verstehe es irgendwie, aber dann verstehe ich es nicht gleichzeitig.

Ich fand diese Antwort hier sehr hilfreich:

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

Um aus Idan Arye zu zitieren:

Um auf Ihrer Geschichte aufzubauen, würde ich so etwas sagen:

Sie sehen sich den Cartoon an, aber es ist das Intro. Anstatt das Intro zu sehen, wechseln Sie zum Spiel und betreten die Online-Lobby - aber es werden 3 Spieler benötigt und nur Sie und Ihre Schwester sind dabei. Anstatt darauf zu warten, dass ein anderer Spieler zu Ihnen kommt, wechseln Sie zu Ihren Hausaufgaben und beantworten Sie die erste Frage. Die zweite Frage enthält einen Link zu einem YouTube-Video, das Sie ansehen müssen. Sie öffnen es - und es wird geladen. Anstatt darauf zu warten, dass es geladen wird, wechseln Sie zurück zum Cartoon. Das Intro ist vorbei, Sie können also zuschauen. Jetzt gibt es Werbespots - aber mittlerweile ist ein dritter Spieler beigetreten, sodass Sie zum Spiel wechseln und so weiter ...

Die Idee ist, dass Sie die Aufgaben nicht einfach sehr schnell wechseln, damit es so aussieht, als würden Sie alles auf einmal erledigen. Sie nutzen die Zeit, die Sie darauf warten, dass etwas passiert (IO), um andere Dinge zu tun, die Ihre direkte Aufmerksamkeit erfordern.

Überprüfen Sie auf jeden Fall den Link, es gibt noch viel mehr, dass ich nicht alles zitieren kann.


6
Sehr einfache und unkomplizierte Darstellung. +1 dafür.
Taslim Oseni

tolle Illustration. Ich habe eine ähnliche Geschichte geschrieben - mit Schlange stehen und darauf warten, ein Paket abzuholen. Aber für heute ist Ihre viel realistischer. Wer steht in der Schlange, wenn es Tür-Tür-Lieferungen gibt? Lol
Apolak

1
Das ist eine großartige Erklärung. Aus dem Zitat selbst geht hervor, dass es sehr klar ist.
Farruh Habibullaev

15

Coroutine ähnelt Subroutine / Threads. Der Unterschied besteht darin, dass ein Aufrufer, sobald er eine Unterroutine / Threads aufgerufen hat, niemals mehr zur Aufruferfunktion zurückkehrt. Eine Coroutine kann jedoch nach dem Ausführen einiger Codeteile zum Aufrufer zurückkehren, sodass der Aufrufer einen Teil seines eigenen Codes ausführen und zum Coroutine-Punkt zurückkehren kann, an dem die Ausführung gestoppt wurde, und von dort aus fortfahren kann. dh. Eine Coroutine hat mehr als einen Ein- und Ausstiegspunkt


Es ist nicht so ähnlich wie Threads - die unabhängig und gleichzeitig laufen (separate Kerne parallel). Darüber hinaus schlägt der Unterprogrammvergleich in dem Sinne fehl, dass es mehrere unabhängige Ausführungspfade gibt und sie keine Ergebnisse untereinander zurückgeben.
Javadba

11
  • Coroutinen sind großartige Funktionen, die in der Kotlin-Sprache verfügbar sind
  • Coroutinen sind eine neue Art, asynchronen, nicht blockierenden Code (und vieles mehr) zu schreiben.
  • Coroutine sind leichte Fäden. Ein leichter Thread bedeutet, dass er nicht auf nativen Threads abgebildet wird, sodass kein Kontextwechsel auf dem Prozessor erforderlich ist, sodass sie schneller sind.
  • Es wird nicht auf nativen Thread abgebildet
  • Coroutinen und die Threads sind beide Multitasking. Der Unterschied besteht jedoch darin, dass Threads vom Betriebssystem und Coroutinen von den Benutzern verwaltet werden.

Grundsätzlich gibt es zwei Arten von Coroutinen:

  1. Stapellos
  2. Stapelhaft

Kotlin implementiert stapellose Coroutinen - es bedeutet, dass die Coroutinen keinen eigenen Stapel haben, sodass sie nicht auf nativen Threads abgebildet werden.

Dies sind die Funktionen zum Starten der Coroutine:

launch{}

async{}

Hier können Sie mehr lernen:

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

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


1
Gute Antwort! Nützlich für Kotlin- und Android-Entwickler.
Malwinder Singh

5

In der Python- geventBibliothek befindet sich eine coroutinebasierte Netzwerkbibliothek, die Ihnen threadähnliche Funktionen wie asynchrone Netzwerkanforderungen bietet, ohne den Aufwand für das Erstellen und Zerstören von Threads. Die verwendete coroutineBibliothek ist greenlet.


2

Von Python Coroutine :

Die Ausführung von Python-Coroutinen kann an vielen Stellen angehalten und fortgesetzt werden (siehe Coroutine). Warten und asynchrone Bezeichner werden im Hauptteil einer Coroutine-Funktion zu reservierten Schlüsselwörtern. Warten auf Ausdrücke, Async for und Async with können nur in Coroutine-Funktionskörpern verwendet werden.

Aus Coroutinen (C ++ 20)

Eine Coroutine ist eine Funktion, die die Ausführung unterbrechen kann, um später wieder aufgenommen zu werden . Coroutinen sind stapellos: Sie unterbrechen die Ausführung, indem sie zum Aufrufer zurückkehren. Dies ermöglicht sequentiellen Code, der asynchron ausgeführt wird (z. B. um nicht blockierende E / A ohne explizite Rückrufe zu verarbeiten) und unterstützt auch Algorithmen für verzögert berechnete unendliche Sequenzen und andere Verwendungen.

Vergleichen Sie mit der Antwort anderer:

Meiner Meinung nach ist der später wieder aufgenommene Teil ein wesentlicher Unterschied, genau wie bei @ Twinkle.
Obwohl viele Felder des Dokuments noch in Arbeit sind, ähnelt dieser Teil den meisten Antworten, mit Ausnahme von @Nan Xiaos

Coroutinen hingegen sind kollaborativ: Zu einem bestimmten Zeitpunkt führt ein Programm mit Coroutinen nur eine seiner Coroutinen aus, und diese ausgeführte Coroutine setzt ihre Ausführung nur dann aus, wenn sie ausdrücklich die Suspendierung anfordert.

Da es aus dem Programm in Lua zitiert wird, ist es möglicherweise sprachbezogen (derzeit nicht mit Lua vertraut), nicht alle Dokumente erwähnen den einzigen Teil.

Die Beziehung zur gleichzeitigen:
Es gibt einen "Execution" -Teil der Coroutines (C ++ 20). Zu lange, um hier zu zitieren.
Neben dem Detail gibt es mehrere Zustände.

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 

als Kommentar von @Adam Arold unter der Antwort von @ user217714. Es ist Parallelität.
Aber es unterscheidet sich vom Multithreading. von std :: thread

Threads ermöglichen die gleichzeitige Ausführung mehrerer Funktionen. Die Ausführung von Threads beginnt unmittelbar nach der Erstellung des zugeordneten Thread-Objekts (bis zu Verzögerungen bei der Betriebssystemplanung), beginnend mit der Funktion der obersten Ebene, die als Konstruktorargument bereitgestellt wird. Der Rückgabewert der Funktion der obersten Ebene wird ignoriert. Wenn sie durch Auslösen einer Ausnahme beendet wird, wird std :: terminate aufgerufen. Die Funktion der obersten Ebene kann dem Aufrufer ihren Rückgabewert oder eine Ausnahme über std :: versprechen oder durch Ändern gemeinsam genutzter Variablen (die möglicherweise eine Synchronisierung erfordern, siehe std :: mutex und std :: atomic) mitteilen.

Da es sich um eine Parallelität handelt, funktioniert es wie Multithreading, insbesondere wenn das Warten unvermeidlich ist (aus Sicht des Betriebssystems). Deshalb ist es auch verwirrend.


1

Eine Coroutine ist eine spezielle Art von Unterprogramm. Anstelle der Master-Slave-Beziehung zwischen einem Aufrufer und einem aufgerufenen Unterprogramm, die bei herkömmlichen Unterprogrammen besteht, sind Anrufer und aufgerufene Coroutinen gerechter.

  • Eine Coroutine ist ein Unterprogramm, das mehrere Einträge enthält und diese selbst steuert - direkt in Lua unterstützt

  • Auch als symmetrische Steuerung bezeichnet: Anrufer und angerufene Coroutinen sind gleichberechtigter

  • Ein Coroutine-Anruf wird als Lebenslauf bezeichnet

  • Die erste Wiederaufnahme einer Coroutine beginnt, aber nachfolgende Aufrufe werden an der Stelle unmittelbar nach der zuletzt ausgeführten Anweisung in der Coroutine eingegeben

  • Coroutinen nehmen sich wiederholt wieder auf, möglicherweise für immer

  • Coroutinen ermöglichen die quasi gleichzeitige Ausführung von Programmeinheiten (die Coroutinen); ihre Ausführung ist verschachtelt, aber nicht überlappend

Beispiel 1 Beispiel2


1

Ich finde eine Erklärung von diesem Link ist ziemlich einfach. Keine dieser Antworten versucht, Parallelität und Parallelität zu erklären, mit Ausnahme des letzten Aufzählungspunkts in dieser Antwort .

  1. Was ist gleichzeitig (Programm)?

zitiert aus "Programmierung Erlang" von Joe Armstrong, dem legendären:

Ein gleichzeitiges Programm kann auf einem parallelen Computer möglicherweise schneller ausgeführt werden.

  • Ein gleichzeitiges Programm ist ein Programm, das in einer gleichzeitigen Programmiersprache geschrieben ist. Wir schreiben gleichzeitig Programme aus Gründen der Leistung, Skalierbarkeit oder Fehlertoleranz.

  • Eine gleichzeitige Programmiersprache ist eine Sprache mit expliziten Sprachkonstrukten zum Schreiben gleichzeitiger Programme. Diese Konstrukte sind ein wesentlicher Bestandteil der Programmiersprache und verhalten sich auf allen Betriebssystemen gleich.

  • Ein Parallelcomputer ist ein Computer mit mehreren Prozessoreinheiten (CPUs oder Kernen), die gleichzeitig ausgeführt werden können.

Parallelität ist also nicht dasselbe wie Parallelität. Sie können weiterhin gleichzeitig Programme auf einem Single-Core-Computer schreiben. Mit dem Time-Sharing-Planer haben Sie das Gefühl, dass Ihr Programm gleichzeitig ausgeführt wird.

Das gleichzeitige Programm kann möglicherweise parallel auf einem parallelen Computer ausgeführt werden, ist jedoch nicht garantiert . Das Betriebssystem bietet Ihnen möglicherweise nur einen Kern zum Ausführen Ihres Programms.

Daher Gleichzeitigkeit ist ein Software - Modell von einem gleichzeitigen Programm , das Ihr Programm nicht bedeuten kann physisch parallel laufen.

  1. Coroutine und Parallelität

Das Wort "Coroutine" besteht aus zwei Wörtern: "Co" (kooperativ) und "Routinen" (Funktionen).

ein. erreicht es Parallelität oder Parallelität?

Um es einfach zu machen, lassen Sie es uns auf einem einzigen Kern diskutieren Computer .

Parallelität wird durch Time-Shares vom Betriebssystem erreicht. Ein Thread führt seinen Code in den ihm zugewiesenen Zeitrahmen auf dem CPU-Kern aus. Es kann vom Betriebssystem vorbelegt werden. Es kann auch die Kontrolle über das Betriebssystem ermöglichen.

Eine Coroutine hingegen gibt einer anderen Coroutine innerhalb des Threads die Kontrolle, nicht dem Betriebssystem. Daher nutzen alle Coroutinen innerhalb eines Threads immer noch den Zeitrahmen für diesen Thread, ohne den CPU-Kern anderen vom Betriebssystem verwalteten Threads zu überlassen.

Daher kann man sich vorstellen , dass Coroutine Zeitanteile durch den Benutzer erzielt, nicht durch das Betriebssystem (oder Quasi-Parallelität). Coroutinen werden auf demselben Kern ausgeführt, der dem Thread zugewiesen ist, der diese Koroutinen ausführt.

Erreicht Coroutine Parallelität? Wenn es sich um CPU-gebundenen Code handelt, nein. Wie bei Time-Shares haben Sie das Gefühl, dass sie parallel laufen, ihre Ausführungen jedoch verschachtelt und nicht überlappend sind. Wenn es E / A-gebunden ist, wird es parallel durch Hardware (E / A-Geräte) und nicht durch Ihren Code erreicht.

b. der Unterschied zum Funktionsaufruf?

Geben Sie hier die Bildbeschreibung ein

Wie das Bild zeigt, muss kein Anruf getätigt werden, returnum die Steuerung zu wechseln. Es kann ohne nachgeben return. Eine Coroutine speichert und teilt den Status im aktuellen Funktionsrahmen (Stapel). Es ist also viel leichter als die Funktion, da Sie keine Register und lokalen Variablen speichern müssen, um den Aufrufstapel zu stapeln und zurückzuspulen, wenn call ret.


0

Ich werde die Antwort von @ user21714 erweitern. Coroutinen sind unabhängige Ausführungspfade, die nicht gleichzeitig ausgeführt werden können. Sie hängen von einem Controller - beispielsweise einer pythonController-Bibliothek - ab, um das Umschalten zwischen diesen Pfaden zu handhaben. Damit dies funktioniert, müssen die Coroutinen selbst yieldoder ähnliche Strukturen aufrufen , mit denen ihre Ausführung angehalten werden kann.

Threads werden stattdessen auf unabhängigen Rechenressourcen und parallel zueinander ausgeführt. Da sie sich auf unterschiedlichen Ressourcen befinden, muss Yield nicht aufgerufen werden , damit die anderen Ausführungspfade fortgesetzt werden können.

Sie können diesen Effekt sehen, indem Sie ein Programm mit mehreren Threads starten - z. B. eine jvmAnwendung -, in der alle acht core i7Hyperthread-Kerne verwendet werden. Möglicherweise wird in Activity Monitoroder eine Auslastung von 797% angezeigt Top. Stattdessen wird beim Ausführen eines typischen pythonProgramms - auch eines mit coroutinesoder python threading- die maximale Auslastung bei 100% liegen. Dh ein Maschinen-Hyperthread.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.