如何在 GenServer 中使用 Task.await?
How to use Task.await with GenServer?
我正在想办法启动一个 genserver,等待结果直到它完成。
如何让服务器 return 退出时成为结果?
例如:
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)
那么,我将如何等待并获得结果?
这里有一种方法:在:load
cast
、return的结果中long_process
作为新的状态。然后添加一个 call
,它只是 return 当前状态(下面命名为 :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 秒多一点。
我正在想办法启动一个 genserver,等待结果直到它完成。
如何让服务器 return 退出时成为结果?
例如:
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)
那么,我将如何等待并获得结果?
这里有一种方法:在:load
cast
、return的结果中long_process
作为新的状态。然后添加一个 call
,它只是 return 当前状态(下面命名为 :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 秒多一点。