GenServer :Continue 调用是同步的吗?

Dav*_*aze 3 elixir gen-server

实现GenServer handle_call/3可以返回:continue以调用附加函数。是否可以保证此函数相对于其他消息的运行时间?

例如,考虑这个仅保留运行计数器的模块:

defmodule Tmp do
  use GenServer

  def start_link(opts), do: GenServer.start_link(__MODULE__, 0, opts)
  def incr(tmp), do: GenServer.call(tmp, :incr)

  @impl true
  def init(state), do: {:ok, state}

  @impl true
  def handle_call(:incr, _from, n) do
    {:reply, n, n, {:continue, :incr}}
  end

  @impl true
  def handle_continue(:incr, n) do
    {:noreply, n+1}
  end
end
Run Code Online (Sandbox Code Playgroud)

当您调用 时Tmp.incr/1,该handle_call/3方法返回计数器的当前值,但随后也返回:continue。这会导致GenServer基础设施调用handle_continue/2

如果我Tmp.incr/1连续调用两次,我能保证得到递增的值吗?或者是否有可能在被调用handle_call/3之前被调用两次?handle_continue/2

iex> {:ok, tmp} = Tmp.start_link([])
iex> Tmp.incr(tmp)
0
iex> Tmp.incr(tmp)
1
# If I type fast enough, will this ever return 0?
Run Code Online (Sandbox Code Playgroud)

Leo*_*ino 5

是的,:continue是同步的 - continue 将在您返回它的函数之后立即执行。它的用例正是这样的:保证它将在之后立即运行,这是其他方法无法保证的,例如:timeout或使用 向自己发送消息send(self(), :incr)

GenServer 回调的文档中简要提到了这一点:

返回 {:reply,reply,new_state,{:continue, continue}} 与 {:reply,reply,new_state} 类似,除了将在之后立即调用 handle_continue/2,并将值 continue 作为第一个参数。

另外在超时部分

由于消息可能在设置超时之前到达,因此即使超时为 0 毫秒也不能保证执行。要立即无条件地执行另一个操作,请使用 :Continue 指令。