Eine Einführung in die ETS-Tabellen in Elixir

Wenn Sie ein Elixier-Programm erstellen, müssen Sie häufig einen Status gemeinsam nutzen. In einem meiner vorherigen Artikel habe ich zum Beispiel gezeigt, wie ein Server codiert wird, um verschiedene Berechnungen durchzuführen und das Ergebnis im Speicher zu halten (und später haben wir gesehen, wie dieser Server mithilfe von Supervisoren kugelsicher gemacht wird). Es gibt jedoch ein Problem: Wenn Sie einen einzelnen Prozess haben, der sich um den Status und viele andere Prozesse kümmert, die auf ihn zugreifen, kann die Leistung ernsthaft beeinträchtigt werden. Dies liegt einfach daran, dass der Prozess nur jeweils eine Anfrage bearbeiten kann. 

Es gibt jedoch Möglichkeiten, dieses Problem zu überwinden, und heute werden wir über eines von ihnen sprechen. Treffen Sie Erlang Term Storage-Tische oder einfach ETS-Tabellen, ein schneller In-Memory-Speicher, der Tupel beliebiger Daten aufnehmen kann. Wie der Name schon sagt, wurden diese Tabellen ursprünglich in Erlang eingeführt, aber wie jedes andere Erlang-Modul können wir sie auch in Elixir verwenden.

In diesem Artikel werden Sie:

  • Erfahren Sie, wie Sie ETS-Tabellen und -Optionen erstellen, die bei der Erstellung verfügbar sind.
  • Erfahren Sie, wie Sie Lesen, Schreiben, Löschen und einige andere Operationen ausführen.
  • Siehe ETS-Tabellen in Aktion.
  • Informieren Sie sich über festplattenbasierte ETS-Tabellen und wie sie sich von In-Memory-Tabellen unterscheiden.
  • Sehen Sie, wie Sie ETS und DETS hin und her konvertieren.

Alle Codebeispiele funktionieren mit Elixir 1.4 und 1.5, das kürzlich veröffentlicht wurde.

Einführung in die ETS-Tabellen

Wie bereits erwähnt, sind ETS-Tabellen In-Memory-Speicher, der Daten-Tupel (als Zeilen bezeichnet) enthält. Mehrere Prozesse können auf die Tabelle über ihre ID oder einen als Atom dargestellten Namen zugreifen und Lese-, Schreib-, Lösch- und andere Operationen ausführen. ETS-Tabellen werden von einem separaten Prozess erstellt. Wenn dieser Prozess beendet wird, wird die Tabelle zerstört. Es gibt jedoch keinen automatischen Speicherbereinigungsmechanismus, sodass die Tabelle längere Zeit im Speicher hängen bleibt.

Daten in der ETS-Tabelle werden durch ein Tupel dargestellt : key, value1, value2, valuen. Sie können die Daten einfach anhand des Schlüssels nachschlagen oder eine neue Zeile einfügen. Standardmäßig können jedoch nicht zwei Zeilen mit demselben Schlüssel vorhanden sein. Schlüsselbasierte Operationen sind sehr schnell. Wenn Sie jedoch aus irgendeinem Grund eine Liste aus einer ETS-Tabelle erstellen und beispielsweise komplexe Manipulationen der Daten vornehmen müssen, ist dies auch möglich.

Darüber hinaus stehen festplattenbasierte ETS-Tabellen zur Verfügung, die ihren Inhalt in einer Datei speichern. Natürlich arbeiten sie langsamer, aber auf diese Weise erhalten Sie eine einfache Dateispeicherung ohne Probleme. Außerdem können In-Memory-ETS problemlos auf Festplattenbasis und umgekehrt konvertiert werden.

Ich denke, es ist an der Zeit, unsere Reise zu beginnen und zu sehen, wie die ETS-Tabellen erstellt werden!

ETS-Tabelle erstellen

Verwenden Sie zum Erstellen einer ETS-Tabelle die neu / 2 Funktion. Solange wir ein Erlang-Modul verwenden, sollte sein Name als Atom geschrieben werden:

cool_table =: ets.new (: cool_table, [])

Bis vor kurzem konnten Sie nur bis zu 1.400 Tabellen pro BEAM-Instanz erstellen. Dies ist jedoch nicht mehr der Fall. Sie sind nur auf den verfügbaren Speicher beschränkt.

Das erste Argument ging an die Neu Funktion ist der Name der Tabelle (Alias), während die zweite eine Liste von Optionen enthält. Das cool_table Variable enthält jetzt eine Nummer, die die Tabelle im System identifiziert:

IO.inspect cool_table # => 12306

Sie können diese Variable jetzt verwenden, um nachfolgende Operationen an der Tabelle auszuführen (z. B. Daten lesen und schreiben)..

Verfügbare Optionen

Lassen Sie uns über die Optionen sprechen, die Sie beim Erstellen einer Tabelle angeben können. Die erste (und etwas seltsame) Bemerkung ist, dass Sie den Alias ​​der Tabelle standardmäßig nicht verwenden können und im Wesentlichen keine Auswirkung haben. Aber immer noch der Alias Muss auf die Schaffung der Tabelle übergeben werden.

Um auf die Tabelle über ihren Alias ​​zugreifen zu können, müssen Sie ein angeben : named_table Option wie folgt:

cool_table =: ets.new (: cool_table, [: named_table])

Wenn Sie die Tabelle umbenennen möchten, können Sie dies übrigens mit der umbenennen / 2 Funktion:

: ets.rename (cool_table,: cooler_table)

Als nächstes kann, wie bereits erwähnt, eine Tabelle nicht mehrere Zeilen mit demselben Schlüssel enthalten, und dies wird durch den Befehl diktiert Art. Es gibt vier mögliche Tabellentypen:

  • :einstellen-das ist die Standardeinstellung. Das bedeutet, dass Sie nicht mehrere Zeilen mit genau denselben Schlüsseln haben können. Die Zeilen werden auf keine bestimmte Weise neu angeordnet.
  • : order_set-das Gleiche wie :einstellen, aber die Reihen sind nach den Begriffen geordnet.
  • :Tasche-Mehrere Zeilen können denselben Schlüssel haben, die Zeilen können jedoch immer noch nicht vollständig identisch sein.
  • : duplicate_bag-Zeilen können völlig identisch sein.

Es gibt eine Sache, die es zu erwähnen gilt : order_set Tische. Wie in der Dokumentation von Erlang beschrieben, behandeln diese Tabellen Schlüssel als gleich, wenn sie gleich sind Vergleiche gleich, nicht nur wenn sie Spiel. Was bedeutet das?

Zwei Begriffe in Erlang stimmen nur überein, wenn sie denselben Wert und denselben Typ haben. Also ganzzahlig 1 stimmt nur mit einer anderen Ganzzahl überein 1, aber nicht schweben 1,0 da sie verschiedene Arten haben. Zwei Terme sind jedoch gleich, wenn sie den gleichen Wert und Typ haben oder wenn beide numerisch sind und sich auf denselben Wert erstrecken. Das bedeutet, dass 1 und 1,0 sind vergleichbar.

Um den Typ der Tabelle anzugeben, fügen Sie der Liste der Optionen einfach ein Element hinzu:

cool_table =: ets.new (: cool_table, [: named_table,: order_set])

Eine weitere interessante Option, die Sie passieren können, ist : komprimiert. Dies bedeutet, dass die Daten in der Tabelle (aber nicht die Schlüssel) erraten werden, was in einer kompakten Form gespeichert wird. Natürlich werden die Operationen, die für die Tabelle ausgeführt werden, langsamer.

Als Nächstes können Sie steuern, welches Element im Tupel als Schlüssel verwendet werden soll. Standardmäßig das erste Element (Position 1) wird verwendet, dies kann jedoch leicht geändert werden:

cool_table =: ets.new (: cool_table, [: keypos, 2])

Nun werden die zweiten Elemente in den Tupeln als Schlüssel behandelt.

Die letzte, aber nicht die letzte Option steuert die Zugriffsrechte der Tabelle. Diese Rechte legen fest, welche Prozesse auf die Tabelle zugreifen können:

  • :Öffentlichkeit-Jeder Prozess kann eine beliebige Operation an der Tabelle ausführen.
  • :geschützt-der Standardwert Nur der Eigentümerprozess kann in die Tabelle schreiben, aber alle Prozesse können lesen.
  • :Privatgelände-Nur der Eigentümerprozess kann auf die Tabelle zugreifen.

Um eine Tabelle privat zu machen, würden Sie schreiben:

cool_table =: ets.new (: cool_table, [: private])

Okay, genug über Optionen geredet - einige typische Operationen, die Sie an den Tabellen ausführen können!

Schreibvorgänge

Um etwas aus der Tabelle zu lesen, müssen Sie zuerst einige Daten dort schreiben. Beginnen wir also mit der letzteren Operation. Verwenden Sie die einfügen / 2 Funktion, um Daten in die Tabelle einzufügen:

cool_table =: ets.new (: cool_table, []): ets.insert (cool_table, : number, 5)

Sie können auch eine Liste von Tupeln wie folgt übergeben:

: ets.insert (cool_table, [: number, 5, : string, "test"])

Beachten Sie, wenn die Tabelle einen Typ hat :einstellen Wenn ein neuer Schlüssel mit einem vorhandenen Schlüssel übereinstimmt, werden die alten Daten überschrieben. Ähnlich, wenn eine Tabelle einen Typ von hat : order_set Wenn ein neuer Schlüssel mit dem alten verglichen wird, werden die Daten überschrieben. Achten Sie also darauf.

Die Einfügeoperation (auch mit mehreren Tupeln gleichzeitig) ist garantiert atomar und isoliert, was bedeutet, dass entweder alles in der Tabelle gespeichert ist oder gar nichts. Andere Prozesse können das Zwischenergebnis der Operation auch nicht sehen. Alles in allem ist dies SQL-Transaktionen ziemlich ähnlich.

Wenn Sie befürchten, Schlüssel zu duplizieren, oder Ihre Daten nicht versehentlich überschreiben möchten, verwenden Sie die insert_new / 2 Funktion stattdessen. Es ist ähnlich wie einfügen / 2 fügt jedoch niemals doppelte Schlüssel ein und kehrt stattdessen zurück falsch. Dies ist der Fall für die :Tasche und : duplicate_bag auch tische:

cool_table =: ets.new (: cool_table, [: bag]): ets.insert (cool_table, : number, 5): ets.insert_new (cool_table, : number, 6) |> IO.inspect # = > falsch

Wenn Sie eine Liste von Tupeln angeben, wird jede Taste überprüft und der Vorgang wird abgebrochen, auch wenn eine der Tasten doppelt vorhanden ist.

Operationen lesen

Toll, jetzt haben wir einige Daten in unserer Tabelle - wie holen wir sie ab? Der einfachste Weg ist die Suche nach einem Schlüssel:

: ets.insert (cool_table, : number, 5) IO.inspect: ets.lookup (cool_table,: number) # => [number: 5]

Denken Sie daran, dass für die : order_set In der Tabelle sollte der Schlüssel dem angegebenen Wert entsprechen. Bei allen anderen Tabellentypen sollte es übereinstimmen. Auch wenn ein Tisch ein ist :Tasche oder ein : order_bag, das Nachschlagen / 2 Funktion kann eine Liste mit mehreren Elementen zurückgeben:

cool_table =: ets.new (: cool_table, [: bag]): ets.insert (cool_table, [: number, 5, : number, 6]) IO.inspect: ets.lookup (cool_table,: number.) ) # => [Anzahl: 5, Anzahl: 6]

Anstatt eine Liste abzurufen, können Sie mit der Taste ein Element an der gewünschten Position greifen lookup_element / 3 Funktion:

cool_table =: ets.new (: cool_table, []): ets.insert (cool_table, : number, 6) IO.inspect: ets.lookup_element (cool_table,: number, 2) # => 6

In diesem Code erhalten wir die Zeile unter dem Schlüssel :Nummer und dann das Element in die zweite Position bringen. Es funktioniert auch perfekt mit :Tasche oder : duplicate_bag:

cool_table =: ets.new (: cool_table, [: bag]): ets.insert (cool_table, [: number, 5, : number, 6]) , 2) # => 5,6

Wenn Sie einfach prüfen möchten, ob ein Schlüssel in der Tabelle vorhanden ist, verwenden Sie Mitglied / 2, was entweder zurückkehrt wahr oder falsch:

cool_table =: ets.new (: cool_table, [: bag]): ets.insert (cool_table, [: number, 5, : number, 6]) wenn: ets.member (cool_table,: number) IO.inspect: ets.lookup_element (cool_table,: number, 2) # => 5,6 end

Sie können auch den ersten oder den letzten Schlüssel in einer Tabelle erhalten, indem Sie verwenden erste / 1 und letzte / 1 beziehungsweise:

cool_table =: ets.new (: cool_table, [: Sorted_set]): ets.insert (cool_table, [: b, 3, : a, 100]): ets.last (cool_table) |> IO.inspect # =>: b: ets.first (cool_table) |> IO.inspect # =>: a

Darüber hinaus ist es möglich, den vorherigen oder den nächsten Schlüssel anhand des bereitgestellten Schlüssels zu bestimmen. Wenn ein solcher Schlüssel nicht gefunden werden kann, : "$ end_of_table" Wird zurückgegeben:

cool_table =: ets.new (: cool_table, [: Sorted_set]): ets.insert (cool_table, [: b, 3, : a, 100]): ets.prev (cool_table,: b) |> IO.inspect # =>: a: ets.next (cool_table,: a) |> IO.inspect # =>: b: ets.prev (cool_table,: a) |> IO.inspect # =>: "$ end_of_table "

Beachten Sie jedoch, dass die Tabelle mit Funktionen wie zuerst, Nächster, zuletzt oder vorheriges ist nicht isoliert. Dies bedeutet, dass ein Prozess möglicherweise weitere Daten entfernt oder zur Tabelle hinzufügt, während Sie darüber iterieren. Eine Möglichkeit, dieses Problem zu überwinden, ist die Verwendung von safe_fixtable / 2, Dadurch wird die Tabelle repariert und sichergestellt, dass jedes Element nur einmal abgerufen wird. Die Tabelle bleibt fest, es sei denn, der Prozess gibt sie frei:

cool_table =: ets.new (: cool_table, [: bag]): ets.safe_fixtable (cool_table, true): ets.info (cool_table,: safe_fixed_monotonic_time) |> IO.inspect # => 256000, [#PID<0.69.0>, 1]: ets.safe_fixtable (cool_table, false) # => Die Tabelle wird zu diesem Zeitpunkt freigegeben: ets.info (cool_table,: safe_fixed_monotonic_time) |> IO.inspect # => false

Wenn Sie ein Element in der Tabelle finden und entfernen möchten, verwenden Sie das Nimm 2 Funktion:

cool_table =: ets.new (: cool_table, [: Sorted_set]): ets.insert (cool_table, [: b, 3, : a, 100]): ets.take (cool_table,: b) |> IO.inspect # => [b: 3]: ets.take (cool_table,: b) |> IO.inspect # => []

Operationen löschen

Okay, jetzt sagen wir, Sie brauchen den Tisch nicht mehr und möchten ihn loswerden. Benutzen löschen / 1 dafür:

cool_table =: ets.new (: cool_table, [: order_set]): ets.delete (cool_table)

Natürlich können Sie eine Zeile (oder mehrere Zeilen) auch nach ihrem Schlüssel löschen:

cool_table =: ets.new (: cool_table, []): ets.insert (cool_table, [: b, 3, : a, 100])): ets.delete (cool_table,: a)

Um die gesamte Tabelle zu löschen, verwenden Sie delete_all_objects / 1:

cool_table =: ets.new (: cool_table, []): ets.insert (cool_table, [: b, 3, : a, 100]): ets.delete_all_objects (cool_table)

Um ein bestimmtes Objekt zu finden und zu entfernen, verwenden Sie delete_object / 2:

cool_table =: ets.new (: cool_table, [: bag]): ets.insert (cool_table, [: a, 3, : a, 100]): ets.delete_object (cool_table, : a, 3 ): ets.lookup (cool_table,: a) |> IO.inspect # => [a: 100]

Die Tabelle konvertieren

Eine ETS-Tabelle kann jederzeit in eine Liste konvertiert werden tab2list / 1 Funktion:

cool_table =: ets.new (: cool_table, [: bag]): ets.insert (cool_table, [: a, 3, : a, 100]): ets.tab2list (cool_table) |> IO.inspect # => [a: 3, a: 100]

Denken Sie jedoch daran, dass das Abrufen der Daten aus der Tabelle über die Tasten eine sehr schnelle Operation ist, und wenn möglich, sollten Sie sich daran halten.

Sie können Ihre Tabelle auch mit einer Datei sichern tab2file / 2:

cool_table =: ets.new (: cool_table, [: bag]): ets.insert (cool_table, [: a, 3, : a, 100]): ets.tab2file (cool_table, 'cool_table.txt' ) |> IO.inspect # =>: ok

Beachten Sie, dass das zweite Argument eine charlist (ein String mit einfachen Anführungszeichen) sein sollte..

Es gibt eine Handvoll anderer Operationen, die auf die ETS-Tabellen angewendet werden können. Natürlich werden wir nicht alle besprechen. Ich empfehle wirklich, die Erlang-Dokumentation zu ETS durchzugehen, um mehr zu erfahren.

Den Staat mit ETS beharren

Um die bisher gesammelten Fakten zusammenzufassen, wollen wir ein einfaches Programm modifizieren, das ich in meinem Artikel über GenServer vorgestellt habe. Dies ist ein Modul namens CalcServer So können Sie verschiedene Berechnungen durchführen, indem Sie Anforderungen an den Server senden oder das Ergebnis abrufen:

defmodule CalcServer verwendet GenServer def start (initial_value) do GenServer.start (__ MODULE__, initial_value, name: __MODULE__) end def init (initial_value), wenn is_number (initial_value) do : ok, initial_value do def: init (_) do : stop, "Der Wert muss eine ganze Zahl sein!" ) do GenServer.cast (__ MODULE__, : multiplizieren, number) end def div (number) do GenServer.cast (__ MODULE__, : div, number) end def Ergebnis do GenServer.call (__ MODULE__,: result) end def handle_call (: result, _, state) do : antworten, state, state end def handle_cast (operation, state) do case operation do: sqrt -> : noreply,: math.sqrt (state) : multiplizieren, multiplier -> : noreply, state * multiplier : div, number -> : noreply, state / number : addieren, number -> : noreply, state + number _ -> : stop , "Nicht implementiert", state end end def terminate (_reason, _state) do IO.puts "Der Serverabschluss ted "end end CalcServer.start (6.1) CalcServer.sqrt CalcServer.multiply (2) CalcServer.result |> IO.puts # => 4.9396356140913875

Derzeit unterstützt unser Server nicht alle mathematischen Operationen, Sie können sie jedoch bei Bedarf erweitern. In meinem anderen Artikel wird außerdem erläutert, wie Sie dieses Modul in eine Anwendung konvertieren und Supervisoren dazu nutzen, Serverabstürze zu vermeiden.

Was ich jetzt tun möchte, ist ein weiteres Feature hinzuzufügen: die Möglichkeit, alle mathematischen Operationen zu protokollieren, die zusammen mit dem übergebenen Argument ausgeführt wurden. Diese Operationen werden in einer ETS-Tabelle gespeichert, damit wir sie später abrufen können.

Ändern Sie zunächst die drin Funktion, damit eine neue benannte private Tabelle mit einem Typ von : duplicate_bag geschaffen. Wir benutzen : duplicate_bag weil zwei identische Operationen mit demselben Argument ausgeführt werden können:

 def init (initial_value) Wenn is_number (initial_value) Folgendes tut: ets.new (: calc_log, [: duplicate_bag,: private,: named_table]]) : ok, initial_value end

Jetzt optimieren Sie die handle_cast Rückruf, damit der angeforderte Vorgang protokolliert, eine Formel vorbereitet und dann die eigentliche Berechnung ausgeführt wird:

 def handle_cast (operation, state) führt die Operation |> prepare_and_log |> berechne (state) Ende aus

Hier ist der prepare_and_log private Funktion:

 defp prepar_and_log (operation) do operation |> log case Operation do: sqrt -> fn (current_value) ->: math.sqrt (current_value) end : multiplizieren, number -> fn (current_value) -> current_value * number end  : div, number -> fn (current_value) -> current_value / number end : add, number -> fn (current_value) -> current_value + number end _ -> nil end end

Wir protokollieren die Operation sofort (die entsprechende Funktion wird sofort angezeigt). Dann die entsprechende Funktion oder zurücksenden Null wenn wir nicht wissen, wie wir mit der Operation umgehen sollen.

Wie für die Log Wenn wir diese Funktion verwenden, sollten wir entweder ein Tupel (das sowohl den Namen der Operation als auch das Argument enthält) oder ein Atom (das nur den Namen der Operation enthält) unterstützen, : sqrt):

 Def-Protokoll (Vorgang), wenn is_tuple (Vorgang) Folgendes tut: ets.insert (: calc_log, Vorgang) Ende def-Protokoll (Vorgang), wenn is_atom (Vorgang) Folgendes tun: ets.insert (: calc_log, Vorgang, Null) Def-Protokoll beenden (_) do: ets.insert (: calc_log, : unsupported_operation, nil) end

Als nächstes die Berechnung Funktion, die entweder ein korrektes Ergebnis oder eine Stoppnachricht zurückgibt:

 defp berechne (func, state), wenn is_function (func) do : noreply, func. (state) end defp berechne (_func, state) do : stop, "Nicht implementiert", state end

Lassen Sie uns zum Schluss eine neue Schnittstellenfunktion vorstellen, um alle durchgeführten Operationen nach ihrem Typ abzurufen:

 def-Vorgänge (Typ) enden GenServer.call (__ MODULE__, : Vorgänge, Typ)

Behandeln Sie den Anruf:

 def handle_call (: Operationen, Typ, _, State) do : Reply, Fetch_operations_by (Typ), State Ende

Und führen Sie die eigentliche Suche durch:

 defp fetch_operations_by (type) do: ets.lookup (: calc_log, type) Ende

Jetzt alles testen:

CalcServer.start (6.1) CalcServer.sqrt CalcServer.add (1) CalcServer.multiply (2) CalcServer.add (2) CalcServer.result |> IO.inspect # => 8.939635614091387 CalcServer.operations (: add) |> IO. inspect # => [add: 1, add: 2]

Das Ergebnis ist korrekt, weil wir zwei durchgeführt haben :hinzufügen Operationen mit den Argumenten 1 und 2. Sie können dieses Programm natürlich beliebig erweitern. Missbrauchen Sie trotzdem keine ETS-Tabellen und setzen Sie sie ein, wenn die Leistung wirklich gesteigert wird. In vielen Fällen ist die Verwendung von unveränderlichen Gegenständen die bessere Lösung.

Disk ETS

Bevor ich diesen Artikel zusammenfasse, wollte ich ein paar Worte zu festplattenbasierten ETS-Tabellen oder einfach zu DETS sagen. 

DETS sind der ETS ziemlich ähnlich: Sie verwenden Tabellen, um verschiedene Daten in Form von Tupeln zu speichern. Der Unterschied besteht, wie Sie bereits vermutet haben, darin, dass sie auf Dateispeicherung statt auf Arbeitsspeicher angewiesen sind und weniger Funktionen haben. DETS haben ähnliche Funktionen wie die oben beschriebenen, einige Operationen werden jedoch etwas anders ausgeführt.

Um eine Tabelle zu öffnen, müssen Sie eine der beiden verwenden open_file / 1 oder open_file / 2-es gibt kein neu / 2 funktionieren wie im : ets Modul. Da wir noch keinen Tisch haben, bleiben wir bei open_file / 2, welches eine neue Datei für uns erstellt:

: dets.open_file (: file_table, [])

Der Dateiname entspricht standardmäßig dem Namen der Tabelle. Dies kann jedoch geändert werden. Das zweite Argument wurde an die übergeben Datei öffnen ist die Liste der Optionen in Form von Tupeln. Es gibt eine Handvoll von verfügbaren Optionen wie :Zugriff oder : auto_save. Um beispielsweise einen Dateinamen zu ändern, verwenden Sie die folgende Option:

: dets.open_file (: file_table, [: file, 'cool_table.txt'])

Beachten Sie, dass es auch eine gibt :Art Option, die einen der folgenden Werte haben kann:

  • :einstellen
  • :Tasche
  • : duplicate_bag

Diese Typen sind die gleichen wie für die ETS. Beachten Sie, dass DETS keinen Typ von haben kann : order_set.

Es gibt kein : named_table Option, damit Sie immer auf den Namen der Tabelle zugreifen können.

Erwähnenswert ist auch, dass die DETS-Tabellen ordnungsgemäß geschlossen werden müssen:

: dets.close (: file_table)

Wenn Sie dies nicht tun, wird die Tabelle beim nächsten Öffnen repariert.

Sie führen Lese- und Schreibvorgänge wie bei ETS aus:

: dets.open_file (: file_table, [: file, 'cool_table.txt']): dets.insert (: file_table, : a, 3): dets.lookup (: file_table,: a) |> IO .inspect # => [a: 3]: dets.close (: file_table)

Beachten Sie jedoch, dass DETS langsamer sind als ETS, da Elixir auf die Festplatte zugreifen muss, was natürlich mehr Zeit in Anspruch nimmt.

Beachten Sie, dass Sie ETS- und DETS-Tabellen problemlos vor und zurück konvertieren können. Lassen Sie uns zum Beispiel verwenden to_ets / 2 und kopieren Sie den Inhalt unserer DETS-Tabelle im Speicher:

: dets.open_file (: file_table, [: file, 'cool_table.txt'])): dets.insert (: file_table, : a, 3) my_ets =: ets.new (: my_ets, []): dets.to_ets (: file_table, my_ets): dets.close (: file_table): ets.lookup (my_ets,: a) |> IO.inspect # => [a: 3]

Kopieren Sie den Inhalt der ETS mit DETS nach DETS to_dets / 2:

my_ets =: ets.new (: my_ets, []): ets.insert (my_ets, : a, 3): dets.open_file (: file_table, [: file, 'cool_table.txt']): ets .to_dets (my_ets,: file_table): dets.lookup (: file_table,: a) |> IO.inspect # => [a: 3]: dets.close (: file_table)

Zusammenfassend lässt sich sagen, dass die festplattenbasierte ETS eine einfache Methode zum Speichern von Inhalten in der Datei ist. Dieses Modul ist jedoch etwas weniger leistungsfähig als die ETS und die Vorgänge sind ebenfalls langsamer.

Fazit

In diesem Artikel haben wir über ETS- und plattenbasierte ETS-Tabellen gesprochen, mit denen beliebige Begriffe im Arbeitsspeicher bzw. in Dateien gespeichert werden können. Wir haben gesehen, wie solche Tabellen erstellt werden, welche Typen verfügbar sind, wie Lese- und Schreiboperationen ausgeführt werden, wie Tabellen zerstört werden und wie sie in andere Typen konvertiert werden. Weitere Informationen zu ETS finden Sie im Elixir-Führer und auf der offiziellen Seite von Erlang.

Überbeanspruchen Sie ETS-Tabellen nicht erneut und versuchen Sie, bei unveränderlichen Objekten zu bleiben, wenn möglich. In einigen Fällen kann ETS jedoch eine gute Leistungssteigerung darstellen, daher ist es in jedem Fall hilfreich, sich über diese Lösung zu informieren. 

Hoffentlich hat Ihnen dieser Artikel gefallen. Vielen Dank, dass Sie bei mir geblieben sind und bis bald!