English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Lua-Synchronisationsprogramme(coroutine)

Was ist eine Collaboration (coroutine)?

Lua Collaborative Programme (coroutine) sind ähnlich wie Threads: Sie haben eigenen Stack, eigene lokale Variablen, eigenen Befehlszeiger und teilen gleichzeitig globale Variablen und andere Dinge mit anderen Collaborationsprogrammen.

Collaboration ist eine sehr starke Funktion, aber sie ist auch sehr komplex zu verwenden.

Thread und Collaborative Programme Unterschied

Der Hauptunterschied zwischen Threads und Kollaborationen liegt darin, dass ein Programm mit mehreren Threads mehrere Threads gleichzeitig ausführen kann, während Kollaborationen zusammenarbeiten müssen, um zu arbeiten.

Zu jedem beliebigen Zeitpunkt läuft nur ein Kollaboration, und die laufende Kollaboration wird nur dann gehängt, wenn sie ausdrücklich angefordert wird

Kollaborationen sind etwas ähnlich wie synchrone Mehrkerntreads, einige Threads, die auf denselben Thread-Schutzschlüssel warten, sind etwas ähnlich Kollaborationen.

Grund语法

MethodeBeschreibung
coroutine.create()Erstellt ein coroutine, gibt ein coroutine zurück, das Argument ist eine Funktion, wenn es zusammen mit resume verwendet wird, wird die Funktion aufgeweckt
coroutine.resume()coroutine neu starten, zusammen mit create verwenden
coroutine.yield()coroutine hängen lassen, den Zustand des coroutines auf suspended setzen, was zusammen mit resume viele nützliche Effekte haben kann
coroutine.status()Status eines coroutines anzeigen
Anmerkung: Der Zustand eines coroutines kann dreierlei sein: tot, suspended, laufend, wann genau solche Zustände auftreten, siehe das folgende Programm
coroutine.wrap()Erstellt ein coroutine, gibt eine Funktion zurück, sobald diese Funktion aufgerufen wird, tritt das coroutine ein, was der Funktion create ähnelt
coroutine.running()Gibt den laufenden coroutine zurück, ein coroutine ist ein Thread, wenn "laufend" verwendet wird, wird die Thread-Nummer eines coroutines zurückgegeben

Der folgende Beispiel zeigt die Verwendung der oben genannten Methoden:

-- coroutine_test.lua Datei
co = coroutine.create(
    function(i)
        print(i);
    end
)
 
coroutine.resume(co, 1)   -- 1
print(coroutine.status(co))  -- tot
 
print("----------")
 
co = coroutine.wrap(
    function(i)
        print(i);
    end
)
 
co(1)
 
print("----------")
 
co2 = coroutine.create(
    function()
        for i=1,10 tun
            print(i)
            if i == 3 dann
                print(coroutine.status(co2))  --laufend
                print(coroutine.laufend()) --thread:XXXXXX
            end
            coroutine.yield()
        end
    end
)
 
coroutine.resume(co2) --1
coroutine.resume(co2) --2
coroutine.resume(co2) --3
 
print(coroutine.status(co2))   -- suspended
print(coroutine.laufend())
 
print("----------")

Die Ausgabe des obigen Beispiels beträgt:

1
tot
----------
1
----------
1
2
3
laufend
thread: 0x7fb801c05868    false
suspended
thread: 0x7fb801c04c88    true
----------

coroutine.running zeigt, dass coroutine im Untergrund eine Thread ist.

Wenn ein Koroutinen erstellt wird, wird ein Ereignis in einem neuen Thread registriert.

Wenn der Aufruf von resume ein Ereignis auslöst, wird die coroutine-Funktion von create ausgeführt. Wenn yield erreicht wird, bedeutet das, dass der aktuelle Thread pausiert wird und auf den erneuten Aufruf von resume durch ein Ereignis gewartet wird.

Nun analysieren wir ein detaillierteres Beispiel:

function foo (a)
    print("foo Funktionsausgabe", a)
    return coroutine.yield(2 * a) -- zurückgeben  2*Der Wert von a
end
 
co = coroutine.create(function (a , b)
    print("Erste Koroutinen-Ausführungsausgabe", a, b) -- co-body 1 10
    local r = foo(a + 1)
     
    print("Zweiter Koroutinen-Ausführungsausgabe", r)
    local r, s = coroutine.yield(a + b, a - b)  -- Die Werte von a, b sind die, die beim ersten Aufruf des Koroutinen übergeben werden
     
    print("Dritter Koroutinen-Ausführungsausgabe", r, s)
    return b, "Koroutinen beenden"                   -- Der Wert von b ist der, der beim zweiten Aufruf des Koroutinen übergeben wird
end)
        
print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("--Trennlinie----")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("---Trennlinie---")
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("---Trennlinie---")
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
print("---Trennlinie---")

Die Ausgabe des obigen Beispiels beträgt:

Erste Koroutinen-Ausführungsausgabe    1    10
foo-Funktionsausgabe    2
main  true    4
--Trennlinie----
Zweiter Koroutinen-Ausführungsausgabe    r
main  true    11    -9
---Trennlinie---
Dritter Koroutinen-Ausführungsausgabe    x    y
main  true    10    Koroutinen beenden
---Trennlinie---
main  false  cannot resume dead coroutine
---Trennlinie---

Der obige Beispiel fortgesetzt wie folgt:

  • Aufruf von resume, um den Koroutinen zu wecken, resume gibt erfolgreich zurück, wenn der Vorgang erfolgreich ist, sonst gibt er false zurück;

  • Koroutinen werden ausgeführt;

  • Bis zum yield-Ausdruck ausführen;

  • Der Yield-Syntask pausiert den Koroutinen, der erste Aufruf von resume gibt zurück;(Hinweis: Hier gibt yield zurück, der Parameter ist der von resume übergebene Parameter)

  • Zweite resume, das Synchronisationsprogramm wird erneut geweckt;(Beachten Sie: Die zusätzlichen Parameter im resume-Parameter sind die Parameter für yield)

  • yield zurückgeben;

  • Synchronisationsprogramm fortsetzen;

  • Wenn der Synchronisationsprogramm nach dem Fortsetzen der Ausführung weiterhin den resume-Methodenaufruf ausführt, wird ausgegeben: cannot resume dead coroutine

Die starke Seite der Kombination von resume und yield liegt darin, dass resume im Hauptprogramm steht und den externen Zustand (Daten) in das Synchronisationsprogramm einbringt; während yield den internen Zustand (Daten) in das Hauptprogramm zurückbringt.

Produzent-Verbraucherproblem

Ich werde jetzt die Synchronisationsprogramme von Lua verwenden, um das Produzentenproblem zu lösen-Das klassische Verbraucherproblem.

local newProductor
function productor()
     local i = 0
     while true do
          i = i + 1
          send(i)     -- Senden Sie das hergestellte Item an den Verbraucher
     end
end
function consumer()
     while true do
          local i = receive()     -- Erhalte das Item vom Produzenten
          print(i)
     end
end
function receive()
     local status, value = coroutine.resume(newProductor)
     return value
end
function send(x)
     coroutine.yield(x)     -- x bedeutet den zu sendenden Wert, nach dem Wert wird der Synchronisationsprogramm angehalten
end
-- Programm starten
newProductor = coroutine.create(productor)
consumer()

Die Ausgabe des obigen Beispiels beträgt:

1
2
3
4
5
6
7
8
9
10
11
12
13
……