在 Elixir 中启动同一事件处理程序的多个实例
Launching multiple instances of the same event handler in Elixir
我在 elixir 中有一个简单的事件处理程序,使用 GenEvent
:
defmodule myHandler do
use GenEvent
#Callback
def handle_event {:message, x}, state do
IO.puts("Message value is #{x}")
{:ok, [x|state]}
end
end
我可以用通常的方式启动一个处理程序和一个管理器:
{:ok, mgr} = GenEvent.start_link
myServer.start_link(mgr)
GenEvent.add_handler(mgr,myHandler, [])
但是,我想启动一个监督树,其中有 N 个处理程序,每个处理程序都有不同的 ID,使用相同的管理器。
我试过了:
Gen.Event.add_handler({mgr, :id1},myHandler, [])
,没有运气!相反,我收到以下错误:
** (Mix) Could not start application : exited in: myApp.start(:normal, [])
** (EXIT) no connection to :id1
我是 Elixir 的新手,所以我对文档有点费劲。如果有人能告诉我怎么做,我将不胜感激!谢谢。
你总是可以在 MyHandler
中拥有更复杂的状态:
defmodule MyHandler do
use GenEvent
def handle_event({:message, id, message}, {id, messages}) do
IO.puts "[ID: #{inspect id}] Message value is #{inspect message}."
{:ok, {id, [message | messages]}}
end
def handle_event(_, state) do
{:ok, state}
end
end
要按 id 过滤消息,我会将消息结构更改为:
{:message, id, message}
如果不这样做,每个处理程序都会打印相同的消息。我猜这就是你想要 ID 的原因。
然后有一个 id
,你可以这样做:
{:ok, manager} = GenEvent.start_link
MyServer.start_link manager
GenEvent.add_handler manager, MyHandler, {id, []}
如您所见,新状态是 {id :: atom, messages :: list}
而不是简单的消息列表。
那么发送消息就可以了:
GenServer.sync_notify manager, {:message, id, message}
示例:
初始化管理器:
iex(1)> {:ok, manager} = GenEvent.start_link
{:ok, #PID<0.75.0>}
添加处理程序:
iex(2)> GenEvent.add_handler manager, MyHandler, {:id0, []}
:ok
测试 ID 为 :id0
的消息并打印消息:
iex(3)> GenEvent.sync_notify manager, {:message, :id0, "Hello"}
[ID: :id0] Message value is "Hello".
:ok
用不存在的 ID :id1
测试一条消息,它不打印任何内容:
iex(4)> GenEvent.sync_notify manager, {:message, :id1, "Hello"}
:ok
给你。我希望这会有所帮助:)
P.S:如果你的状态太复杂,你总是可以使用map:
%{id: id, messages: []}
事实证明,要将多个处理程序添加到同一个管理器,您需要遵循以下原则:
GenEvent.add_handler(:myManager, {myHandler, :id1}, [])
我把争论搞砸了 - 感谢 Elixir slack 频道上精彩的@true_droid。
我在 elixir 中有一个简单的事件处理程序,使用 GenEvent
:
defmodule myHandler do
use GenEvent
#Callback
def handle_event {:message, x}, state do
IO.puts("Message value is #{x}")
{:ok, [x|state]}
end
end
我可以用通常的方式启动一个处理程序和一个管理器:
{:ok, mgr} = GenEvent.start_link
myServer.start_link(mgr)
GenEvent.add_handler(mgr,myHandler, [])
但是,我想启动一个监督树,其中有 N 个处理程序,每个处理程序都有不同的 ID,使用相同的管理器。
我试过了:
Gen.Event.add_handler({mgr, :id1},myHandler, [])
,没有运气!相反,我收到以下错误:
** (Mix) Could not start application : exited in: myApp.start(:normal, [])
** (EXIT) no connection to :id1
我是 Elixir 的新手,所以我对文档有点费劲。如果有人能告诉我怎么做,我将不胜感激!谢谢。
你总是可以在 MyHandler
中拥有更复杂的状态:
defmodule MyHandler do
use GenEvent
def handle_event({:message, id, message}, {id, messages}) do
IO.puts "[ID: #{inspect id}] Message value is #{inspect message}."
{:ok, {id, [message | messages]}}
end
def handle_event(_, state) do
{:ok, state}
end
end
要按 id 过滤消息,我会将消息结构更改为:
{:message, id, message}
如果不这样做,每个处理程序都会打印相同的消息。我猜这就是你想要 ID 的原因。
然后有一个 id
,你可以这样做:
{:ok, manager} = GenEvent.start_link
MyServer.start_link manager
GenEvent.add_handler manager, MyHandler, {id, []}
如您所见,新状态是 {id :: atom, messages :: list}
而不是简单的消息列表。
那么发送消息就可以了:
GenServer.sync_notify manager, {:message, id, message}
示例:
初始化管理器:
iex(1)> {:ok, manager} = GenEvent.start_link
{:ok, #PID<0.75.0>}
添加处理程序:
iex(2)> GenEvent.add_handler manager, MyHandler, {:id0, []}
:ok
测试 ID 为 :id0
的消息并打印消息:
iex(3)> GenEvent.sync_notify manager, {:message, :id0, "Hello"}
[ID: :id0] Message value is "Hello".
:ok
用不存在的 ID :id1
测试一条消息,它不打印任何内容:
iex(4)> GenEvent.sync_notify manager, {:message, :id1, "Hello"}
:ok
给你。我希望这会有所帮助:)
P.S:如果你的状态太复杂,你总是可以使用map:
%{id: id, messages: []}
事实证明,要将多个处理程序添加到同一个管理器,您需要遵循以下原则:
GenEvent.add_handler(:myManager, {myHandler, :id1}, [])
我把争论搞砸了 - 感谢 Elixir slack 频道上精彩的@true_droid。