Lua - Coroutinen
Einführung
Coroutinen sind kollaborativer Natur, wodurch zwei oder mehr Methoden kontrolliert ausgeführt werden können. Bei Coroutinen wird zu einem bestimmten Zeitpunkt nur eine Coroutine ausgeführt, und diese laufende Coroutine setzt ihre Ausführung nur dann aus, wenn sie ausdrücklich die Unterbrechung anfordert.
Die obige Definition kann vage aussehen. Nehmen wir an, wir haben zwei Methoden, eine die Hauptprogrammmethode und eine Coroutine. Wenn wir eine Coroutine mit der Resume-Funktion aufrufen, wird sie ausgeführt, und wenn wir die Yield-Funktion aufrufen, wird die Ausführung angehalten. Wiederum kann dieselbe Coroutine mit einem anderen Funktionsaufruf zur Wiederaufnahme fortgesetzt werden, von dem aus sie angehalten wurde. Dieser Vorgang kann bis zum Ende der Ausführung der Coroutine fortgesetzt werden.
In Coroutinen verfügbare Funktionen
In der folgenden Tabelle sind alle verfügbaren Funktionen für Coroutinen in Lua und ihre entsprechende Verwendung aufgeführt.
Sr.Nr. | Methode & Zweck |
---|---|
1 | coroutine.create (f) Erstellt eine neue Coroutine mit der Funktion f und gibt ein Objekt vom Typ "thread" zurück. |
2 | coroutine.resume (co [, val1, ...]) Setzt die Coroutine co fort und übergibt die Parameter, falls vorhanden. Es gibt den Betriebsstatus und optional andere Rückgabewerte zurück. |
3 | coroutine.running () Gibt die laufende Coroutine oder Null zurück, wenn sie im Hauptthread aufgerufen wird. |
4 | coroutine.status (co) Gibt einen der Werte aus "Laufen", "Normal", "Angehalten" oder "Tot" basierend auf dem Status der Coroutine zurück. |
5 | coroutine.wrap (f) Wie coroutine.create erstellt auch die Funktion coroutine.wrap eine Coroutine, aber anstatt die Coroutine selbst zurückzugeben, gibt sie eine Funktion zurück, die beim Aufruf die Coroutine wieder aufnimmt. |
6 | coroutine.yield (...) Hält die laufende Coroutine an. Der an diese Methode übergebene Parameter dient als zusätzliche Rückgabewerte für die Wiederaufnahmefunktion. |
Beispiel
Schauen wir uns ein Beispiel an, um das Konzept der Coroutinen zu verstehen.
co = coroutine.create(function (value1,value2)
local tempvar3 = 10
print("coroutine section 1", value1, value2, tempvar3)
local tempvar1 = coroutine.yield(value1+1,value2+1)
tempvar3 = tempvar3 + value1
print("coroutine section 2",tempvar1 ,tempvar2, tempvar3)
local tempvar1, tempvar2= coroutine.yield(value1+value2, value1-value2)
tempvar3 = tempvar3 + value1
print("coroutine section 3",tempvar1,tempvar2, tempvar3)
return value2, "end"
end)
print("main", coroutine.resume(co, 3, 2))
print("main", coroutine.resume(co, 12,14))
print("main", coroutine.resume(co, 5, 6))
print("main", coroutine.resume(co, 10, 20))
Wenn wir das obige Programm ausführen, erhalten wir die folgende Ausgabe.
coroutine section 1 3 2 10
main true 4 3
coroutine section 2 12 nil 13
main true 5 1
coroutine section 3 5 6 16
main true 2 end
main false cannot resume dead coroutine
Was macht das obige Beispiel?
Wie bereits erwähnt, verwenden wir die Wiederaufnahmefunktion, um die Operation zu starten, und die Yield-Funktion, um die Operation zu stoppen. Sie können auch sehen, dass mehrere Rückgabewerte von der Wiederaufnahmefunktion von Coroutine empfangen werden.
Zuerst erstellen wir eine Coroutine und weisen sie einem Variablennamen co zu. Die Coroutine nimmt zwei Variablen als Parameter auf.
Wenn wir die erste Wiederaufnahmefunktion aufrufen, bleiben die Werte 3 und 2 in den temporären Variablen value1 und value2 bis zum Ende der Coroutine erhalten.
Um dies zu verstehen, haben wir eine Tempvar3 verwendet, die anfänglich 10 ist und durch die nachfolgenden Aufrufe der Coroutinen auf 13 und 16 aktualisiert wird, da Wert1 während der Ausführung der Coroutine als 3 beibehalten wird.
Die erste coroutine.yield gibt zwei Werte 4 und 3 an die Resume-Funktion zurück, die wir durch Aktualisieren der Eingabeparameter 3 und 2 in der Yield-Anweisung erhalten. Es erhält auch den True / False-Status der Coroutine-Ausführung.
Eine andere Sache über Coroutinen ist, wie die nächsten Parameter des Wiederaufnahmeaufrufs im obigen Beispiel erledigt werden; Sie können sehen, dass die Variable coroutine.yield die nächsten Aufrufparameter empfängt. Dies bietet eine leistungsstarke Möglichkeit, neue Operationen unter Beibehaltung vorhandener Parameterwerte durchzuführen.
Sobald alle Anweisungen in den Coroutinen ausgeführt wurden, werden die nachfolgenden Aufrufe in false zurückgegeben und die Anweisung "tote Coroutine kann nicht fortgesetzt werden" als Antwort.
Ein weiteres Coroutine-Beispiel
Betrachten wir eine einfache Coroutine, die mit Hilfe der Ertragsfunktion und der Wiederaufnahmefunktion eine Zahl von 1 bis 5 zurückgibt. Es erstellt eine Coroutine, wenn diese nicht verfügbar ist, oder setzt die vorhandene Coroutine fort.
function getNumber()
local function getNumberHelper()
co = coroutine.create(function ()
coroutine.yield(1)
coroutine.yield(2)
coroutine.yield(3)
coroutine.yield(4)
coroutine.yield(5)
end)
return co
end
if(numberHelper) then
status, number = coroutine.resume(numberHelper);
if coroutine.status(numberHelper) == "dead" then
numberHelper = getNumberHelper()
status, number = coroutine.resume(numberHelper);
end
return number
else
numberHelper = getNumberHelper()
status, number = coroutine.resume(numberHelper);
return number
end
end
for index = 1, 10 do
print(index, getNumber())
end
Wenn wir das obige Programm ausführen, erhalten wir die folgende Ausgabe.
1 1
2 2
3 3
4 4
5 5
6 1
7 2
8 3
9 4
10 5
Es gibt oft einen Vergleich von Coroutinen mit den Threads von Multiprogrammiersprachen, aber wir müssen verstehen, dass Coroutinen ähnliche Thread-Funktionen haben, aber jeweils nur eine ausführen und niemals gleichzeitig ausgeführt werden.
Wir steuern die Programmausführungssequenz, um die Anforderungen zu erfüllen, indem bestimmte Informationen vorübergehend aufbewahrt werden. Die Verwendung globaler Variablen mit Coroutinen bietet Coroutinen noch mehr Flexibilität.