GenServer的父进程如何等待其响应?

时间:2017-03-23 17:40:29

标签: elixir

Elixir官方指南中有类似代理的实现

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

使用它时,响应将传递给其调用者进程邮箱

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

但是,当使用实际代理(内部使用GenServer)时,父进程可立即使用响应

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

当我使用代理时,我不需要编写receive块来获取["eggs"],结果已经可用,即使它是一个将数据传递给另一个进程的单独进程。是否可以使用裸流程实现相同的效果,或GenServer使用其他内容?

2 个答案:

答案 0 :(得分:4)

接收块在 play() { this.wavesurfer.play(); } 功能内 - 您不需要手动编写。但基本原则完全相同。

答案 1 :(得分:4)

  

当我使用代理时,我不需要写一个接收块来获取[“eggs”],结果已经可用

你没有写接收,但是Agent.get通过拨打receive来调用GenServer.call which contains the receive间接做:gen.call。只需4行代码即可为代理实现相同的功能:

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)

输出:

42