如何使用 elixir 创建事件发射器,otp 方式

How to create an event emitter with elixir, the otp way

在 elixir 中创建一个在每个给定时间点滴答的前台进程的最佳方法是什么?

我的主要问题是这样的方法:

defmoulde Ticker do
  def tick do
    do_something()
    :timer.sleep(1000)
    tick
  end
end

有效,但设计有误。它绝对不是每秒滴答作响,而是每秒加上 do_something() 完成的时间。 我可以生成一个进程来处理 "something",但仍然有一点延迟。

此外,我正在尝试构建一个混合应用程序,其中涉及一些 GenServers,以及一个主要的前台进程(我在这里问的那个)应该每 x 秒调用一次服务器。有 otp 方法吗?

我认为timer:apply_interval/4应该能满足您的需求。它是这样使用的:

defmodule Tick do
  def tick do
    IO.inspect(:tick)
  end
end

:timer.apply_interval(:timer.seconds(1), Tick, :tick, [])

参数依次是间隔、模块名称、要调用的函数和调用它的参数。然后您可以在该函数内向您的 GenServers 发送消息。在此处查看完整文档:apply_interval/4

另一件需要考虑的事情是,如果您的 tick 函数只向某些 GenServers 发送简单消息,那么它可能 非常 快,所以你的实现可能没问题,一旦包裹在 Task 中并插入监督树(如果你不关心潜在的轻微漂移)。

如果您更喜欢在给定的时间间隔内发送消息而不是调用函数,您可以使用 :timer.send_interval/3

例如如果你想像 OP 在他们的回答中提到的那样每秒向 GenServer 发送一条消息,你可以执行以下操作:

:timer.send_interval(:timer.seconds(1), target_pid, :tick)

其中 target_pid 是您要向其发送消息的 GenServer 的 PID。然后你可以在你的 GenServer 中像这样处理这条消息:

def handle_info(:tick, state) do
  do_something()
  {:noreply, state}
end