Was ist eine Coroutine? Wie hängen sie mit der Parallelität zusammen?
Was ist eine Coroutine? Wie hängen sie mit der Parallelität zusammen?
Antworten:
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.
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.
orthogonal = Not similar to each other
?
orthogonal
bedeutet "unabhängig voneinander".
Aus der Programmierung in Lua , Coroutines
Abschnitt " ":
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 .
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.
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
Grundsätzlich gibt es zwei Arten von Coroutinen:
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
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.
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.
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
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 .
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.
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?
Wie das Bild zeigt, muss kein Anruf getätigt werden, return
um 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
.
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 python
Controller-Bibliothek - ab, um das Umschalten zwischen diesen Pfaden zu handhaben. Damit dies funktioniert, müssen die Coroutinen selbst yield
oder ä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 jvm
Anwendung -, in der alle acht core i7
Hyperthread-Kerne verwendet werden. Möglicherweise wird in Activity Monitor
oder eine Auslastung von 797% angezeigt Top
. Stattdessen wird beim Ausführen eines typischen python
Programms - auch eines mit coroutines
oder python threading
- die maximale Auslastung bei 100% liegen. Dh ein Maschinen-Hyperthread.