Linux + MacOS | Windows |
---|---|
Effil ist eine Multithreading-Bibliothek für Lua. Es ermöglicht die Erzeugung nativer Threads und einen sicheren Datenaustausch. Effil wurde entwickelt, um Lua-Entwicklern eine klare und einfache API bereitzustellen.
Effil unterstützt Lua 5.1, 5.2, 5.3 und LuaJIT. Erfordert C++14-Compiler-Konformität. Getestet mit GCC 4.9+, clang 3.8 und Visual Studio 2015.
git clone --recursive https://github.com/effil/effil effil
cd effil && mkdir build && cd build
cmake .. && make install
luarocks install effil
Wie Sie vielleicht wissen, gibt es nicht viele Skriptsprachen mit echter Multithreading-Unterstützung (Lua/Python/Ruby usw. verfügen über eine globale Interpretersperre, auch bekannt als GIL). Effil löst dieses Problem, indem es unabhängige Lua-VM-Instanzen in separaten nativen Threads ausführt und robuste Kommunikationsprimitive für die Erstellung von Threads und den Datenaustausch bereitstellt.
Die Effil-Bibliothek bietet drei Hauptabstraktionen:
effil.thread
– stellt eine API für die Thread-Verwaltung bereit.effil.table
– stellt eine API für die Tabellenverwaltung bereit. Tabellen können von Threads gemeinsam genutzt werden.effil.channel
– stellt einen First-In-First-Out-Container für den sequentiellen Datenaustausch bereit.Und eine Reihe von Dienstprogrammen zur Verarbeitung von Threads und Tabellen.
local effil = require ( " effil " )
function bark ( name )
print ( name .. " barks from another thread! " )
end
-- run funtion bark in separate thread with name "Spaky"
local thr = effil . thread ( bark )( " Sparky " )
-- wait for completion
thr : wait ()
Ausgabe: Sparky barks from another thread!
local effil = require ( " effil " )
-- channel allow to push data in one thread and pop in other
local channel = effil . channel ()
-- writes some numbers to channel
local function producer ( channel )
for i = 1 , 5 do
print ( " push " .. i )
channel : push ( i )
end
channel : push ( nil )
end
-- read numbers from channels
local function consumer ( channel )
local i = channel : pop ()
while i do
print ( " pop " .. i )
i = channel : pop ()
end
end
-- run producer
local thr = effil . thread ( producer )( channel )
-- run consumer
consumer ( channel )
thr : wait ()
Ausgabe:
push 1
push 2
pop 1
pop 2
push 3
push 4
push 5
pop 3
pop 4
pop 5
effil = require ( " effil " )
-- effil.table transfers data between threads
-- and behaves like regualr lua table
local storage = effil . table { string_field = " first value " }
storage . numeric_field = 100500
storage . function_field = function ( a , b ) return a + b end
storage . table_field = { fist = 1 , second = 2 }
function check_shared_table ( storage )
print ( storage . string_field )
print ( storage . numeric_field )
print ( storage . table_field . first )
print ( storage . table_field . second )
return storage . function_field ( 1 , 2 )
end
local thr = effil . thread ( check_shared_table )( storage )
local ret = thr : get ()
print ( " Thread result: " .. ret )
Ausgabe:
first value
100500
1
2
Thread result: 3
Effil ermöglicht die Übertragung von Daten zwischen Threads (Lua-Interpreter-Zustände) mithilfe von effil.channel
, effil.table
oder direkt als Parameter von effil.thread
.
nil
, boolean
, number
, string
lua_dump
ausgegeben. Aufwertungen werden regelkonform erfasst.lua_iscfunction
„true“ zurückgibt) werden einfach durch einen Zeiger mit lua_tocfunction
(im ursprünglichen lua_State) und lua_pushcfunction (im neuen lua_State) übertragen.lua_iscfunction
true zurück, lua_tocfunction
jedoch nullptr. Aus diesem Grund finden wir keine Möglichkeit, es zwischen lua_States zu übertragen.effil.table
serialisiert. Somit wird jede Lua-Tabelle zu effil.table
. Die Tabellenserialisierung kann bei großen Tabellen viel Zeit in Anspruch nehmen. Daher ist es besser, Daten direkt in effil.table
abzulegen und eine Tabellenserialisierung zu vermeiden. Betrachten wir zwei Beispiele: -- Example #1
t = {}
for i = 1 , 100 do
t [ i ] = i
end
shared_table = effil . table ( t )
-- Example #2
t = effil . table ()
for i = 1 , 100 do
t [ i ] = i
end
Im Beispiel Nr. 1 erstellen wir eine reguläre Tabelle, füllen sie und konvertieren sie in effil.table
. In diesem Fall muss Effil noch einmal alle Tabellenfelder durchgehen. Eine andere Möglichkeit ist Beispiel Nr. 2, bei dem wir zunächst effil.table
erstellt und anschließend Daten direkt in effil.table
eingegeben haben. Der zweite Weg ist viel schneller, versuchen Sie, diesem Prinzip zu folgen.
Alle Vorgänge, die Zeitmetriken verwenden, können blockierend oder nicht blockierend sein und die folgende API verwenden: (time, metric)
wobei metric
ein Zeitintervall wie 's'
(Sekunden) und time
eine Anzahl von Intervallen ist.
Beispiel:
thread:get()
– unendlich auf Thread-Abschluss warten.thread:get(0)
– nicht blockierender Abruf, einfach prüfen, ob der Thread fertig ist, und zurückgebenthread:get(50, "ms")
– Blockierende Wartezeit für 50 Millisekunden.Liste der verfügbaren Zeitintervalle:
ms
– Millisekunden;s
– Sekunden (Standard);m
- Minuten;h
– Stunden.Alle blockierenden Vorgänge (auch im nicht blockierenden Modus) sind Unterbrechungspunkte. Der bei einem solchen Vorgang hängengebliebene Thread kann durch Aufrufen der Methode thread:cancel() unterbrochen werden.
local effil = require " effil "
local worker = effil . thread ( function ()
effil . sleep ( 999 ) -- worker will hang for 999 seconds
end )()
worker : cancel ( 1 ) -- returns true, cause blocking operation was interrupted and thread was cancelled
Beim Arbeiten mit Funktionen serialisiert und deserialisiert Effil diese mithilfe der Methoden lua_dump
und lua_load
. Die Aufwärtswerte aller Funktionen werden nach den gleichen Regeln wie üblich gespeichert. Wenn die Funktion einen Upvalue eines nicht unterstützten Typs hat, kann diese Funktion nicht an Effil übertragen werden. In diesem Fall erhalten Sie eine Fehlermeldung.
Beim Arbeiten mit der Funktion Effil kann auch die Funktionsumgebung ( _ENV
) gespeichert werden. Betrachtet man die Umgebung als reguläre Tabelle, speichert Effil sie auf die gleiche Weise wie jede andere Tabelle. Da es jedoch keinen Sinn macht, global _G
zu speichern, gibt es einige Besonderheiten:
_ENV ~= _G
) übereinstimmt. Der effil.thread
kann mit den entsprechenden Methoden des Thread-Objekts thread:cancel()
und thread:pause()
angehalten und abgebrochen werden.
Der Thread, den Sie zu unterbrechen versuchen, kann an zwei Ausführungspunkten unterbrochen werden: explizit und implizit.
Explizite Punkte sind effil.yield()
local thread = effil . thread ( function ()
while true do
effil . yield ()
end
-- will never reach this line
end )()
thread : cancel ()
Implizite Punkte sind Lua-Debug-Hook-Aufrufe, die mithilfe von lua_sethook mit LUA_MASKCOUNT festgelegt werden.
Implizite Punkte sind optional und nur aktiviert, wenn thread_runner.step > 0.
local thread_runner = effil . thread ( function ()
while true do
end
-- will never reach this line
end )
thread_runner . step = 10
thread = thread_runner ()
thread : cancel ()
Darüber hinaus kann der Thread bei jedem blockierenden oder nicht blockierenden Wartevorgang abgebrochen (aber nicht angehalten) werden.
local channel = effil . channel ()
local thread = effil . thread ( function ()
channel : pop () -- thread hangs waiting infinitely
-- will never reach this line
end )()
thread : cancel ()
Wie funktioniert die Stornierung?
Wenn Sie den Thread abbrechen, wird ein Lua- error
mit der Meldung "Effil: thread is cancelled"
generiert, wenn er einen Unterbrechungspunkt erreicht. Das bedeutet, dass Sie diesen Fehler mit pcall
abfangen können, der Thread jedoch beim nächsten Unterbrechungspunkt einen neuen Fehler generiert.
Wenn Sie Ihren eigenen Fehler abfangen, aber den Abbruchfehler übergeben möchten, können Sie effil.pcall() verwenden.
Der Status des abgebrochenen Threads ist nur dann gleich cancelled
, wenn er mit einem Abbruchfehler beendet wurde. Das bedeutet, dass der Thread möglicherweise mit dem Status completed
oder failed
beendet wird, wenn ein Abbruchfehler auftritt, wenn ein weiterer Fehler auftritt.
effil.thread
ist die Möglichkeit, einen Thread zu erstellen. Threads können gestoppt, pausiert, fortgesetzt und abgebrochen werden. Alle Vorgänge mit Threads können synchron (mit optionalem Timeout) oder asynchron sein. Jeder Thread läuft mit seinem eigenen Lua-Status.
Verwenden Sie effil.table
und effil.channel
um Daten über Threads zu übertragen. Ein Beispiel für die Thread-Nutzung finden Sie hier.
runner = effil.thread(func)
Erstellt einen Thread-Runner. Runner erzeugt für jeden Aufruf einen neuen Thread.
Eingabe : func – Lua-Funktion
Ausgabe : runner – Thread-Runner-Objekt zum Konfigurieren und Ausführen eines neuen Threads
Ermöglicht das Konfigurieren und Ausführen eines neuen Threads.
thread = runner(...)
Führen Sie die erfasste Funktion mit den angegebenen Argumenten in einem separaten Thread aus und geben Sie das Thread-Handle zurück.
Eingabe : Eine beliebige Anzahl von Argumenten, die für die erfasste Funktion erforderlich sind.
Ausgabe : Thread-Handle-Objekt.
runner.path
Ist ein Lua package.path
Wert für den neuen Status. Der Standardwert erbt package.path
vom übergeordneten Status.
runner.cpath
Ist ein Lua package.cpath
Wert für den neuen Status. Der Standardwert erbt package.cpath
vom übergeordneten Status.
runner.step
Anzahl der Lua-Anweisungen Lua zwischen Abbruchpunkten (an denen der Thread gestoppt oder angehalten werden kann). Der Standardwert ist 200. Wenn dieser Wert 0 ist, verwendet der Thread nur explizite Abbruchpunkte.
Das Thread-Handle stellt eine API für die Interaktion mit dem Thread bereit.
status, err, stacktrace = thread:status()
Gibt den Thread-Status zurück.
Ausgabe :
status
– Zeichenfolgenwerte beschreiben den Status des Threads. Mögliche Werte sind: "running", "paused", "cancelled", "completed" and "failed"
.err
– Fehlermeldung, falls vorhanden. Dieser Wert wird nur angegeben, wenn Threadstatus == "failed"
ist.stacktrace
– Stacktrace des fehlgeschlagenen Threads. Dieser Wert wird nur angegeben, wenn Threadstatus == "failed"
ist.... = thread:get(time, metric)
Wartet auf den Abschluss des Threads und gibt im Fehlerfall das Funktionsergebnis oder nichts zurück.
Eingabe : Zeitüberschreitung des Vorgangs in Bezug auf Zeitmetriken
Ausgabe : Ergebnisse des erfassten Funktionsaufrufs oder nichts im Fehlerfall.
thread:wait(time, metric)
Wartet auf den Abschluss des Threads und gibt den Thread-Status zurück.
Eingabe : Zeitüberschreitung des Vorgangs in Bezug auf Zeitmetriken
Ausgabe : Gibt den Status des Threads zurück. Die Ausgabe ist die gleiche wie thread:status()
thread:cancel(time, metric)
Unterbricht die Thread-Ausführung. Sobald diese Funktion aufgerufen wurde, ist das Flag „Abbruch“ gesetzt und der Thread kann irgendwann in der Zukunft gestoppt werden (auch nachdem dieser Funktionsaufruf abgeschlossen ist). Um sicherzustellen, dass der Thread gestoppt wird, rufen Sie diese Funktion mit unendlichem Timeout auf. Das Abbrechen des abgeschlossenen Threads führt zu nichts und gibt true
zurück.
Eingabe : Zeitüberschreitung des Vorgangs in Bezug auf Zeitmetriken
Ausgabe : Gibt true
zurück, wenn der Thread gestoppt wurde, oder false
.
thread:pause(time, metric)
Pausiert den Thread. Sobald diese Funktion aufgerufen wurde, wird das Flag „Pause“ gesetzt und der Thread kann irgendwann in der Zukunft angehalten werden (auch nachdem dieser Funktionsaufruf abgeschlossen ist). Um sicherzustellen, dass der Thread angehalten wird, rufen Sie diese Funktion mit unendlichem Timeout auf.
Eingabe : Zeitüberschreitung des Vorgangs in Bezug auf Zeitmetriken
Ausgabe : Gibt true
zurück, wenn der Thread angehalten wurde, oder false
. Wenn der Thread abgeschlossen ist, gibt die Funktion false
zurück
thread:resume()
Setzt den angehaltenen Thread fort. Die Funktion setzt den Thread sofort fort, wenn er angehalten wurde. Diese Funktion bewirkt nichts für den abgeschlossenen Thread. Die Funktion hat keine Ein- und Ausgabeparameter.
id = effil.thread_id()
Gibt eine eindeutige Kennung an.
Ausgabe : Gibt eine eindeutige Zeichenfolgen id
für den aktuellen Thread zurück.
effil.yield()
Ausdrücklicher Stornierungspunkt. Die Funktion prüft die Abbruch- oder Pausenflags des aktuellen Threads und führt bei Bedarf entsprechende Aktionen aus (Thread abbrechen oder pausieren).
effil.sleep(time, metric)
Aktuellen Thread anhalten.
Eingabe : Argumente für Zeitmetriken.
effil.hardware_threads()
Gibt die Anzahl gleichzeitiger Threads zurück, die von der Implementierung unterstützt werden. Leitet grundsätzlich den Wert von std::thread::hardware_concurrency weiter.
Ausgabe : Anzahl gleichzeitiger Hardware-Threads.
status, ... = effil.pcall(func, ...)
Funktioniert genauso wie der Standard-PCall, außer dass Thread-Abbruchfehler, die durch den Thread:cancel()-Aufruf verursacht werden, nicht abgefangen werden.
Eingang:
Ausgabe:
true
, wenn kein Fehler aufgetreten ist, andernfalls false
effil.table
ist eine Möglichkeit, Daten zwischen effil-Threads auszutauschen. Es verhält sich fast wie Standard-Lua-Tabellen. Alle Vorgänge mit gemeinsam genutzter Tabelle sind Thread-sicher. In einer gemeinsam genutzten Tabelle werden primitive Typen (Zahl, Boolescher Wert, Zeichenfolge), Funktion, Tabelle, leichte Benutzerdaten und effil-basierte Benutzerdaten gespeichert . In der freigegebenen Tabelle werden keine Lua-Threads (Coroutinen) oder beliebige Benutzerdaten gespeichert . Beispiele für die Verwendung gemeinsamer Tabellen finden Sie hier
Verwenden Sie gemeinsam genutzte Tabellen mit regulären Tabellen . Wenn Sie eine reguläre Tabelle in einer gemeinsam genutzten Tabelle speichern möchten, speichert effil implizit die Ursprungstabelle in einer neuen gemeinsam genutzten Tabelle. Gemeinsam genutzte Tabellen speichern Untertabellen immer als gemeinsam genutzte Tabellen.
Verwenden Sie gemeinsam genutzte Tabellen mit Funktionen . Wenn Sie eine Funktion in einer gemeinsam genutzten Tabelle speichern, gibt Effil diese Funktion implizit aus und speichert sie als Zeichenfolge (und ihre Upvalues). Alle Aufwertungswerte der Funktion werden gemäß den folgenden Regeln erfasst.
table = effil.table(tbl)
Erstellt eine neue leere gemeinsame Tabelle.
Eingabe : tbl
– ist ein optionaler Parameter. Es kann sich nur um eine reguläre Lua-Tabelle handeln, deren Einträge in die gemeinsam genutzte Tabelle kopiert werden.
Ausgabe : Neue Instanz einer leeren gemeinsam genutzten Tabelle. Abhängig vom tbl
kann es leer sein oder nicht.
table[key] = value
Legen Sie einen neuen Tabellenschlüssel mit dem angegebenen Wert fest.
Eingabe :
key
– jeder Wert des unterstützten Typs. Sehen Sie sich die Liste der unterstützten Typen anvalue
– jeder Wert des unterstützten Typs. Sehen Sie sich die Liste der unterstützten Typen anvalue = table[key]
Rufen Sie einen Wert aus der Tabelle mit dem angegebenen Schlüssel ab.
Eingabe : key
– jeder Wert des unterstützten Typs. Sehen Sie sich die Liste der unterstützten Typen an
Ausgabe : value
– jeder Wert des unterstützten Typs. Sehen Sie sich die Liste der unterstützten Typen an
tbl = effil.setmetatable(tbl, mtbl)
Setzt eine neue Metatabelle auf eine gemeinsam genutzte Tabelle. Ähnlich dem Standard-Setmetatable.
Eingabe :
tbl
sollte eine gemeinsam genutzte Tabelle sein, für die Sie eine Metatabelle festlegen möchten.mtbl
sollte eine reguläre Tabelle oder eine gemeinsam genutzte Tabelle sein, die zu einer Metatabelle wird. Wenn es sich um eine reguläre Tabelle handelt, erstellt effil eine neue gemeinsam genutzte Tabelle und kopiert alle Felder von mtbl
. Setzen Sie mtbl
auf nil
, um die Metatabelle aus der gemeinsam genutzten Tabelle zu löschen. Ausgabe : Gibt einfach tbl
mit einem neuen metatablen Wert zurück, ähnlich der standardmäßigen Lua- setmetatable -Methode.
mtbl = effil.getmetatable(tbl)
Gibt die aktuelle Metatabelle zurück. Ähnlich wie Standard-getmetatable
Eingabe : tbl
sollte eine gemeinsam genutzte Tabelle sein.
Ausgabe : Gibt die Metatabelle der angegebenen gemeinsam genutzten Tabelle zurück. Die zurückgegebene Tabelle hat immer den Typ effil.table
. Die Standardmetatabelle ist nil
.
tbl = effil.rawset(tbl, key, value)
Tabelleneintrag festlegen, ohne die Metamethode __newindex
aufzurufen. Ähnlich dem Standard-Rawset
Eingabe :
tbl
ist eine gemeinsam genutzte Tabelle.key
– Schlüssel der Tabelle, die überschrieben werden soll. Der Schlüssel kann von jedem unterstützten Typ sein.value
– Wert, der festgelegt werden soll. Der Wert kann von jedem unterstützten Typ sein. Ausgabe : Gibt die gleiche gemeinsam genutzte tbl
zurück
value = effil.rawget(tbl, key)
Ruft den Tabellenwert ab, ohne die Metamethode __index
aufzurufen. Ähnlich wie Standard-Rawget
Eingabe :
tbl
ist eine gemeinsam genutzte Tabelle.key
– Schlüssel der Tabelle zum Empfangen eines bestimmten Werts. Der Schlüssel kann von jedem unterstützten Typ sein. Ausgabe : Gibt den erforderlichen value
zurück, der unter einem angegebenen key
gespeichert ist
effil.G
Ist eine globale vordefinierte gemeinsam genutzte Tabelle. Diese Tabelle ist in jedem Thread (jedem Lua-Status) immer vorhanden.
effil = require " effil "
function job ()
effil = require " effil "
effil . G . key = " value "
end
effil . thread ( job )(): wait ()
print ( effil . G . key ) -- will print "value"
result = effil.dump(obj)
Wandelt effil.table
in eine reguläre Lua-Tabelle um.
tbl = effil . table ({})
effil . type ( tbl ) -- 'effil.table'
effil . type ( effil . dump ( tbl )) -- 'table'
effil.channel
ist eine Möglichkeit, Daten sequentiell zwischen effil-Threads auszutauschen. Es ermöglicht, Nachrichten von einem Thread zu pushen und von einem anderen zu poppen. Die Nachricht des Kanals besteht aus einer Reihe von Werten unterstützter Typen. Alle Operationen mit Kanälen sind Thread-sicher. Beispiele für die Kanalnutzung finden Sie hier
channel = effil.channel(capacity)
Erstellt einen neuen Kanal.
Eingabe : optionale Kapazität des Kanals. Wenn capacity
0
oder nil
beträgt, ist die Kanalgröße unbegrenzt. Die Standardkapazität ist 0
.
Ausgabe : Gibt eine neue Instanz des Kanals zurück.
pushed = channel:push(...)
Schickt die Nachricht an den Kanal.
Eingabe : eine beliebige Anzahl von Werten unterstützter Typen. Mehrere Werte werden als eine einzige Kanalnachricht betrachtet, sodass ein Push an den Kanal die Kapazität um eins verringert.
Ausgabe : pushed
ist gleich true
, wenn der Wert(-s) zur Kanalkapazität passt, andernfalls false
.
... = channel:pop(time, metric)
Pop-Nachricht vom Kanal. Entfernt Werte aus dem Kanal und gibt sie zurück. Wenn der Kanal leer ist, warten Sie auf das Erscheinen eines Werts.
Eingabe : Wartezeitüberschreitung in Bezug auf Zeitmetriken (wird nur verwendet, wenn der Kanal leer ist).
Ausgabe : variable Anzahl von Werten, die von einem einzelnen Kanal:push()-Aufruf gepusht wurden.
size = channel:size()
Erhalten Sie die tatsächliche Anzahl an Nachrichten im Kanal.
Ausgabe : Anzahl der Nachrichten im Kanal.
Effil bietet einen benutzerdefinierten Garbage Collector für effil.table
und effil.channel
(und Funktionen mit erfassten Upvalues). Es ermöglicht die sichere Verwaltung zyklischer Referenzen für Tabellen und Kanäle in mehreren Threads. Dies kann jedoch zu einer zusätzlichen Speichernutzung führen. effil.gc
bietet eine Reihe von Methoden zum Konfigurieren des Efil-Garbage Collectors. Normalerweise müssen Sie es jedoch nicht konfigurieren.
Der Garbage Collector führt seine Arbeit aus, wenn effil ein neues gemeinsames Objekt erstellt (Tabelle, Kanal und Funktionen mit erfassten Up-Werten). Bei jeder GC-Iteration wird die Anzahl der Objekte überprüft. Wenn die Menge der zugewiesenen Objekte den bestimmten Schwellenwert überschreitet, beginnt GC mit der Müllsammlung. Der Schwellenwert wird als previous_count * step
berechnet, wobei previous_count
die Anzahl der Objekte in der vorherigen Iteration ist (standardmäßig 100 ) und step
ein vom Benutzer angegebener numerischer Koeffizient ist (standardmäßig 2,0 ).
Beispiel: Wenn der GC- step
2.0
beträgt und die Anzahl der zugewiesenen Objekte 120
beträgt (übrig nach der vorherigen GC-Iteration), beginnt GC mit der Müllsammlung, wenn die Anzahl der zugewiesenen Objekte 240
beträgt.
Jeder Thread wird als separater Lua-Status mit eigenem Garbage Collector dargestellt. Daher werden Objekte irgendwann gelöscht. Effil-Objekte selbst werden ebenfalls von GC verwaltet und verwenden die Metamethode __gc
userdata als Deserializer-Hook. So erzwingen Sie das Löschen von Objekten:
collectgarbage()
in allen Threads auf.effil.gc.collect()
in einem beliebigen Thread auf.effil.gc.collect()
Erzwingt die Garbage Collection, garantiert jedoch nicht das Löschen aller Efil-Objekte.
count = effil.gc.count()
Anzahl der zugewiesenen gemeinsamen Tische und Kanäle anzeigen.
Ausgabe : Gibt die aktuelle Anzahl der zugewiesenen Objekte zurück. Der Mindestwert ist 1, effil.G
ist immer vorhanden.
old_value = effil.gc.step(new_value)
GC-Speicherschrittmultiplikator abrufen/einstellen. Der Standardwert ist 2.0
. GC löst die Erfassung aus, wenn die Anzahl der zugewiesenen Objekte in step
zunimmt.
Eingabe : new_value
ist der optionale Wert des festzulegenden Schritts. Wenn es nil
ist, gibt die Funktion nur einen aktuellen Wert zurück.
Ausgabe : old_value
ist der aktuelle (wenn new_value == nil
) oder vorherige (wenn new_value ~= nil
) Wert des Schritts.
effil.gc.pause()
GC pausieren. Die Garbage Collection wird nicht automatisch durchgeführt. Die Funktion verfügt über keine Eingabe oder Ausgabe
effil.gc.resume()
GC fortsetzen. Aktivieren Sie die automatische Müllsammlung.
enabled = effil.gc.enabled()
GC-Status abrufen.
Ausgabe : Gibt true
zurück, wenn die automatische Speicherbereinigung aktiviert ist, andernfalls false
. Standardmäßig wird true
zurückgegeben.
size = effil.size(obj)
Gibt die Anzahl der Einträge im Effil-Objekt zurück.
Eingabe : obj
ist eine gemeinsam genutzte Tabelle oder ein gemeinsam genutzter Kanal.
Ausgabe : Anzahl der Einträge in der gemeinsam genutzten Tabelle oder Anzahl der Nachrichten im Kanal
type = effil.type(obj)
Threads, Kanäle und Tabellen sind Benutzerdaten. Daher gibt type()
userdata
für jeden Typ zurück. Wenn Sie den Typ genauer erkennen möchten, verwenden Sie effil.type
. Es verhält sich wie normales type()
, kann jedoch effil-spezifische Benutzerdaten erkennen.
Eingabe : obj
ist ein Objekt eines beliebigen Typs.
Ausgabe : Stringname des Typs. Wenn obj
ein Effil-Objekt ist, gibt die Funktion eine Zeichenfolge wie effil.table
zurück. In anderen Fällen gibt sie das Ergebnis der Funktion „lua_typename“ zurück.
effil . type ( effil . thread ()) == " effil.thread "
effil . type ( effil . table ()) == " effil.table "
effil . type ( effil . channel ()) == " effil.channel "
effil . type ({}) == " table "
effil . type ( 1 ) == " number "