如何在GenServer中使用Task.await?

时间:2018-07-16 12:28:36

标签: elixir gen-server

我试图弄清楚如何启动genserver,并等待结果完成。

我如何使服务器退出时返回结果?

例如:

defmodule DistanceMatrix do
  use GenServer

  def start id do
    GenServer.start(__MODULE__, id)
  end

  def load() do
    GenServer.cast({:load})
  end

  def handle_cast({:load}, state) do
    # start long process operation
    long_process
    {:noreply, state}
  end

  def long_process do
    :timer.sleep 2000
    %{result: "Process result.."}
  end

end 


results= ids
|> Enum.map(fn id -> DistanceMatrix.start(id) end)
|> Enum.map(&Task.await/1)
|> Enum.map(fn({:ok, result}) -> 
   result
   end)

那么,我将如何等待并获得结果?

1 个答案:

答案 0 :(得分:1)

这是一种方法:在:load cast中,返回long_process的结果作为新状态。然后添加一个call,它仅返回当前状态(在下面称为:get)。由于GenServer按照消息发送的顺序顺序处理消息,因此:get调用将一直阻塞,直到前一个:load完成为止。

defmodule DistanceMatrix do
  use GenServer

  def start(id) do
    GenServer.start(__MODULE__, id)
  end

  def load(pid) do
    GenServer.cast(pid, {:load})
    pid
  end

  def await(pid), do: GenServer.call(pid, :get)

  def init(id), do: {:ok, id}

  def handle_call(:get, _, state), do: {:reply, state, state}

  def handle_cast({:load}, _state) do
    {:noreply, long_process()}
  end

  def long_process do
    :timer.sleep(2000)
    %{result: "Process result.."}
  end
end

1..10
|> Enum.map(fn id ->
  {:ok, pid} = DistanceMatrix.start(id)
  pid
end)
|> Enum.map(&DistanceMatrix.load/1)
|> Enum.map(&DistanceMatrix.await/1)
|> Enum.map(fn result ->
  IO.inspect(result)
end)

输出:

%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}
%{result: "Process result.."}

该程序需要2秒钟多一点的时间。