GenServer :continue 调用是同步的吗?
Is a GenServer :continue call synchronous?
A GenServer
handle_call/3
实现可以 return :continue
调用附加函数。是否可以保证此函数何时 运行 相对于其他消息?
例如,考虑这个只保留一个 运行ning 计数器的模块:
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
当您调用 Tmp.incr/1
时,handle_call/3
方法 return 是计数器的当前值,但随后 return 也是 :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?
是的,:continue
是同步的 - continue 将在您从中返回的函数后立即执行。它的use-case就是:保证紧接着就是运行,这是其他方法无法保证的,比如:timeout
或者给自己发消息send(self(), :incr)
。
这在the documentation for GenServer callbacks中有简要提及:
Returning {:reply, reply, new_state, {:continue, continue}} is similar to {:reply, reply, new_state} except handle_continue/2 will be invoked immediately after with the value continue as first argument.
Because a message may arrive before the timeout is set, even a timeout of 0 milliseconds is not guaranteed to execute. To take another action immediately and unconditionally, use a :continue instruction.
A GenServer
handle_call/3
实现可以 return :continue
调用附加函数。是否可以保证此函数何时 运行 相对于其他消息?
例如,考虑这个只保留一个 运行ning 计数器的模块:
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
当您调用 Tmp.incr/1
时,handle_call/3
方法 return 是计数器的当前值,但随后 return 也是 :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?
是的,:continue
是同步的 - continue 将在您从中返回的函数后立即执行。它的use-case就是:保证紧接着就是运行,这是其他方法无法保证的,比如:timeout
或者给自己发消息send(self(), :incr)
。
这在the documentation for GenServer callbacks中有简要提及:
Returning {:reply, reply, new_state, {:continue, continue}} is similar to {:reply, reply, new_state} except handle_continue/2 will be invoked immediately after with the value continue as first argument.
Because a message may arrive before the timeout is set, even a timeout of 0 milliseconds is not guaranteed to execute. To take another action immediately and unconditionally, use a :continue instruction.