2010-12-05 6 views
5

Kurzversion: ist es sicher zu verwenden ets:foldl zu löschen jeden ETS-Datensatz, wie man sie durchläuft?Using ets: foldl als ein armer Mann forEach jedem Datensatz

Angenommen, eine ETS-Tabelle sammelt Informationen, und jetzt ist es an der Zeit, alles zu verarbeiten. Ein Datensatz wird aus der Tabelle gelesen, in irgendeiner Weise verwendet und dann gelöscht. (Angenommen, die Tabelle ist private, also keine Nebenläufigkeitsprobleme.) In einer anderen Sprache mit einer ähnlichen Datenstruktur können Sie eine for ... jede Schleife verwenden, die jeden Datensatz verarbeitet und dann aus dem Hash löscht/dict/Karte/was auch immer. Das ets Modul hat jedoch keine foreach als z.B. lists tut.

Aber das könnte funktionieren:

1> ets:new(ex, [named_table]). 
ex 
2> ets:insert(ex, {alice, "high"}). 
true 
3> ets:insert(ex, {bob, "medium"}). 
true 
4> ets:insert(ex, {charlie, "low"}). 
true 
5> ets:foldl(fun({Name, Adjective}, DontCare) -> 
     io:format("~p has a ~p opinion of you~n", [Name, Adjective]), 
     ets:delete(ex, Name), 
     DontCare 
    end, notused, ex). 
bob has a "medium" opinion of you 
alice has a "high" opinion of you 
charlie has a "low" opinion of you 
notused 
6> ets:info(ex). 
[... 
{size,0}, 
...] 
7> ets:lookup(ex, bob). 
[] 

Ist dies der bevorzugte Ansatz? Ist es zumindest korrekt und fehlerfrei?

Ich habe eine allgemeine Sorge über die Änderung einer Datenstruktur während der Verarbeitung, aber die ets:foldl documentation impliziert, dass ETS ist ziemlich bequem mit Sie Datensätze innerhalb foldl ändern. Da ich den Tisch sauber wische, möchte ich sicher sein.

Ich benutze Erlang R14B mit einer set Tabelle, aber ich würde gerne wissen, ob es Vorbehalte gibt mit irgendeiner Erlang-Version oder irgendeiner Art von Tabelle. Vielen Dank!

Antwort

8

Ihr Ansatz ist sicher. Der Grund, warum es sicher ist, ist, dass ets:foldl/3 intern ets:first/1, ets:next/2 und ets:safe_fixtable/2 verwenden. Diese haben die Garantie, die Sie wollen, nämlich dass Sie Elemente töten können und immer noch den vollen Durchgang erhalten. Siehe den Abschnitt CONCURRENCY von erl -man ets.

Für Ihre Entfernung aller Elemente aus der Tabelle gibt es ein einfacher Einzeiler jedoch:

ets:match_delete(ex, '_'). 

obwohl es nicht funktioniert, sollten Sie die IO-Formatierung für jede Zeile tun wollen, in denen Fall ist Ihr Ansatz mit foldl wahrscheinlich einfacher.

+0

Vielen Dank. Der Abschnitt * Concurrency * der Manpage ist genau das, was ich verpasst habe. Es wird deutlich gesagt, wenn Sie 'safe_fixtable' verwenden, dann wird jedes Objekt einmal besucht. Und ja, in meinem echten Code mache ich natürlich eine komplexe Verarbeitung der Daten, bevor ich sie im Wesentlichen über ets: delete "done" mache. Prost! – JasonSmith

1

In solchen Fällen wechseln wir zwischen zwei Tabellen oder erstellen bei jeder Verarbeitung eine neue Tabelle. Wenn wir einen Verarbeitungszyklus starten wollen, wechseln wir die Writer, um die alternative oder neue Tabelle zu verwenden, dann bearbeiten wir und löschen oder löschen die alte Tabelle.

Wir tun dies, weil sonst möglicherweise gleichzeitige Updates zu einem Tupel, die wir möglicherweise verpassen könnten. Wir arbeiten mit Hochfrequenz-Zählern, wenn wir diese Technik verwenden.

+0

Das ist cool, da es dem Code-Reload-Mechanismus sehr ähnlich ist. Meine anfängliche Sorge - mit Hilfe von faltl als Foreach - ist jetzt gelöst, und es ist gut, daran erinnert zu werden, wie man Zähler richtig pflegt (was ich auch tue). Vielen Dank! – JasonSmith