【发布时间】:2018-01-04 02:59:01
【问题描述】:
我正在尝试使用一个进程作为同步机制,它可以接收我们指定的消息,但仍然可以正常运行。我已经设法用简单的流程实现了我的问题的简化版本,但是我无法使用 GenServer 实现相同的效果。
简化版是这样的:
defmodule Fun do
def start_link do
spawn(fn -> loop(:initiated) end)
end
def loop(state) do
receive do
:join when state == :initiated ->
IO.inspect("Handling join")
loop(:initiated)
:finish when state == :initiated ->
IO.inspect("Finishing")
loop(:finishing)
:cleanup when state == :finishing ->
IO.inspect("Cleaning up...")
end
end
end
上面只会在state为:initiated时处理:join和:finish消息,只有在收到:finish时才执行:cleanup并退出。在这里,我试图利用卡在邮箱中的消息,直到它们可以匹配。
它是这样工作的:
iex(1)> pid = Fun.start_link
#PID<0.140.0>
iex(2)> send(pid, :join)
"Handling join"
:join
iex(3)> send(pid, :join)
"Handling join"
:join
iex(4)> send(pid, :cleanup) # No `IO.inspect` at this point
:cleanup
iex(5)> send(pid, :finish) # Two `IO.inspect`s once `:finish` received
"Finishing"
:finish
"Cleaning up..."
我试图用 GenServer 重现相同的行为:
defmodule FunServer do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(:ok) do
{:ok, :initiated}
end
def handle_info(:join, msg) when msg == :initiated do
IO.inspect("Handling join [From GenServer]")
{:noreply, :initiated}
end
def handle_info(:finish, msg) when msg == :initiated do
IO.inspect("Finishing [From GenServer]")
{:noreply, :finishing}
end
def handle_info(:cleanup, msg) when msg == :finishing do
IO.inspect("Cleaning up [From GenServer]")
{:stop, :normal, msg}
end
end
鉴于我将此 GenServer 配置为 :temporary worker 我的应用程序,它的工作方式如下:
iex(1)> send(FunServer, :join)
"Handling join [From GenServer]"
:join
iex(2)> send(FunServer, :cleanup)
:cleanup
iex(3)>
07:11:17.383 [error] GenServer FunServer terminating
** (FunctionClauseError) no function clause matching in
FunServer.handle_info/2
(what_the_beam) lib/fun_server.ex:22: FunServer.handle_info(:cleanup, :initiated)
(stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:686: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: :cleanup
State: :initiated
我尝试过使用handle_cast 回调,以及不同格式的参数,例如:
handle_info(:cleanup, :finishing)
或
handle_cast(:cleanup, :finishing)
而不是where msg == :finishing,但它们都不适合我。
我正在使用 Elixir 1.5 和 Erlang 20。
【问题讨论】:
标签: elixir erlang-otp