gen_server:reply/2: 发送给客户端的消息格式
gen_server:reply/2: format of message sent to client
当我调用gen_server:reply/2
时:
gen_server:reply(From, Msg),
客户端 From
收到格式为:
的消息
{Ref, Msg)
我找不到关于 gen_server:reply/2
发送的消息格式的任何文档,我想知道如何模式匹配消息中的 Ref
。目前,我对 Ref
:
使用无关变量
receive
{_Ref, Msg} -> Msg;
Other -> Other
end
这意味着 gen_server
以外的进程可能会向我的客户发送一条与 {_Ref, Msg}
子句匹配的消息。
这是一个gen.erl feature used by gen_* behaviors. You can see gen_event's call, gen_server's call and gen_statem's call。
那么它是如何工作的呢?
Idea很简单,当你调用gen:call/4或gen:call(Process, Label, Request, Timeout)
时,它会监听Process
。所以 erlang:monitor/2
产生一个参考。它使用此引用并以 {Label, {self(), Ref}, Request}
的形式向 Process
发送消息。之后它等待 {Ref, Reply}
指定 Timeout
并在收到回复后它 demonitors Process
。此外,如果 Process
在发送 Reply
期间崩溃,或者即使 Process
在调用之前是死的 pid,它也会收到 {'DOWN', Ref, _, _, Reason}
。
例如gen_server:call/2-3
调用gen:call(Prpcess, '$gen_call', Req, Timeout)
。当服务器 Process
(这是一个 gen_server)收到它时,它假定它是一个调用请求,因此调用您的 handle_call 函数等
在调用 gen_server:reply(From, Msg)
中,From
不仅仅是客户端:它实际上是一个包含两个值的元组,调用者的进程 ID 和唯一引用。我们可以在 the implementation of gen_server:reply/2
:
中看到
%% -----------------------------------------------------------------
%% Send a reply to the client.
%% -----------------------------------------------------------------
reply({To, Tag}, Reply) ->
catch To ! {Tag, Reply}.
想法是 Tag
是调用者提供的唯一值,以便调用者可以将此调用的结果与任何其他传入消息区分开来:
Ref = make_ref(),
MyServer ! {'$gen_call', {self(), Ref}, foo},
receive
{Ref, Reply} -> io:format("Result of foo call: ~p~n", [Reply])
end
在上面的代码中,receive
将阻塞,直到它收到对此调用的响应。
(gen_server:call/2
执行与上述类似的操作,并额外监视服务器以防它崩溃,并检查超时。)
之所以没有记录,是因为它被认为是可能更改的内部实现细节,建议用户依赖 gen_server:call
和 gen_server:reply
而不是自己生成和匹配消息。
大多数时候你根本不需要使用 gen_server:reply/2
:服务器进程接收到一个调用并同步处理它,返回一个 reply
元组:
handle_call(foo, _From, State) ->
%% ignoring 'From' here, because we're replying immediately
{reply, foo_result, State}.
但有时您希望服务器进程延迟响应调用,例如等待网络输入:
handle_call(foo, From, State) ->
send_request(foo),
NewState = State#state{pending_request = From},
{noreply, NewState}.
handle_info({received_response, Response}, State = #state{pending_request = From}) ->
gen_server:reply(From, Response),
NewState = State#state{pending_request = undefined},
{noreply, NewState}.
在上面的示例中,我们将 From
值保存在服务器状态中,当响应作为 Erlang 消息传入时,我们将其转发给调用者,调用者将阻塞直到它获得响应. (一个更现实的例子是同时处理多个请求,并以某种方式将传入的响应与未完成的请求进行匹配。)
当我调用gen_server:reply/2
时:
gen_server:reply(From, Msg),
客户端 From
收到格式为:
{Ref, Msg)
我找不到关于 gen_server:reply/2
发送的消息格式的任何文档,我想知道如何模式匹配消息中的 Ref
。目前,我对 Ref
:
receive
{_Ref, Msg} -> Msg;
Other -> Other
end
这意味着 gen_server
以外的进程可能会向我的客户发送一条与 {_Ref, Msg}
子句匹配的消息。
这是一个gen.erl feature used by gen_* behaviors. You can see gen_event's call, gen_server's call and gen_statem's call。
那么它是如何工作的呢?
Idea很简单,当你调用gen:call/4或gen:call(Process, Label, Request, Timeout)
时,它会监听Process
。所以 erlang:monitor/2
产生一个参考。它使用此引用并以 {Label, {self(), Ref}, Request}
的形式向 Process
发送消息。之后它等待 {Ref, Reply}
指定 Timeout
并在收到回复后它 demonitors Process
。此外,如果 Process
在发送 Reply
期间崩溃,或者即使 Process
在调用之前是死的 pid,它也会收到 {'DOWN', Ref, _, _, Reason}
。
例如gen_server:call/2-3
调用gen:call(Prpcess, '$gen_call', Req, Timeout)
。当服务器 Process
(这是一个 gen_server)收到它时,它假定它是一个调用请求,因此调用您的 handle_call 函数等
在调用 gen_server:reply(From, Msg)
中,From
不仅仅是客户端:它实际上是一个包含两个值的元组,调用者的进程 ID 和唯一引用。我们可以在 the implementation of gen_server:reply/2
:
%% -----------------------------------------------------------------
%% Send a reply to the client.
%% -----------------------------------------------------------------
reply({To, Tag}, Reply) ->
catch To ! {Tag, Reply}.
想法是 Tag
是调用者提供的唯一值,以便调用者可以将此调用的结果与任何其他传入消息区分开来:
Ref = make_ref(),
MyServer ! {'$gen_call', {self(), Ref}, foo},
receive
{Ref, Reply} -> io:format("Result of foo call: ~p~n", [Reply])
end
在上面的代码中,receive
将阻塞,直到它收到对此调用的响应。
(gen_server:call/2
执行与上述类似的操作,并额外监视服务器以防它崩溃,并检查超时。)
之所以没有记录,是因为它被认为是可能更改的内部实现细节,建议用户依赖 gen_server:call
和 gen_server:reply
而不是自己生成和匹配消息。
大多数时候你根本不需要使用 gen_server:reply/2
:服务器进程接收到一个调用并同步处理它,返回一个 reply
元组:
handle_call(foo, _From, State) ->
%% ignoring 'From' here, because we're replying immediately
{reply, foo_result, State}.
但有时您希望服务器进程延迟响应调用,例如等待网络输入:
handle_call(foo, From, State) ->
send_request(foo),
NewState = State#state{pending_request = From},
{noreply, NewState}.
handle_info({received_response, Response}, State = #state{pending_request = From}) ->
gen_server:reply(From, Response),
NewState = State#state{pending_request = undefined},
{noreply, NewState}.
在上面的示例中,我们将 From
值保存在服务器状态中,当响应作为 Erlang 消息传入时,我们将其转发给调用者,调用者将阻塞直到它获得响应. (一个更现实的例子是同时处理多个请求,并以某种方式将传入的响应与未完成的请求进行匹配。)