2017-03-23 8 views
1

Es ist ein Mittel, artige Umsetzung von der offiziellen Elixir FührungsWie wartet der Elternprozess von GenServer auf seine Antwort?

defmodule AAgent do 
    def start_agent do 
    spawn_link fn -> loop(%{}) end 
    end 

    def loop(state \\ %{}) do 
    receive do 
     {:put, key, value, caller} -> 
     new_state = Map.put(state, key, value) 
     send caller, new_state 
     loop(new_state) 
     {:get, key, caller} -> 
     send caller, Map.get(state, key) 
     loop(state) 
    end 
    end 
end 

Wenn es verwendet wird, die Antwort auf seine Anrufer Prozess Mailbox geleitet wird

a = AAgent.start_agent 
send a, {:put, :a, 42, self()} 
flush 
%{a: 42} 

Wenn jedoch ein tatsächliches Mittel verwendet wird (die intern verwendet GenServer), die als Reaktion auf den übergeordneten Prozess zur Verfügung steht sofort

iex> Agent.get(agent, fn list -> list end) 
["eggs"] 

ich nicht ne ed, um einen receive Block zu schreiben, um ["eggs"] zu erhalten, wenn ich Agent verwende, das Ergebnis bereits verfügbar, obwohl es ein separater Prozess ist, der Daten an einen anderen Prozess weitergab. Ist es möglich, den gleichen Effekt mit blanken Prozessen zu erreichen, oder nutzt GenServer etwas anderes unter der Haube?

Antwort

4

Ich brauche nicht ein schreiben erhalten Block [ „Eier“] zu erhalten, wenn ich Mittel, um das Ergebnis bereits

Sie nicht schreiben erhalten, aber Agent.get indirekt tut a receive durch Anruf , die :gen.callwhich contains the receive ruft. Sie können mit nur 4 Zeilen Code das gleiche für Ihre Agenten implementieren:

defmodule AAgent do 
    def start_agent do 
    spawn_link fn -> loop(%{}) end 
    end 

    def loop(state \\ %{}) do 
    receive do 
     {:put, key, value, _caller} -> 
     new_state = Map.put(state, key, value) 
     loop(new_state) 
     {:get, key, caller} -> 
     send caller, Map.get(state, key) 
     loop(state) 
    end 
    end 

    def get(agent, key) do 
    send(agent, {:get, key, self()}) 
    receive do x -> x end 
    end 
end 

a = AAgent.start_agent 
send a, {:put, :a, 42, self()} 
IO.inspect AAgent.get(a, :a) 

Ausgang:

42 
4

Der Empfangsblock befindet sich innerhalb der Agent.get/2-Funktion - Sie müssen ihn nicht manuell schreiben. Das zugrunde liegende Prinzip ist jedoch genau das gleiche.

Verwandte Themen