从 handle_cast/handle_call 执行顺序调用 handle_info

Calling handle_info from handle_cast/handle_call order of execution

我有一个 gen_server 但我不明白以下内容:

-module(myserver).
-behaviour(gen_server).
-record(state,{ count=0}).

handle_cast(Message,From,State=#state{count=C})->
     self() ! something,
     {noreply,State}.
handle_info(Message,State=#state{count=C})
      NewCount=case Message of 
                   0 -> C+1;
                   true ->C,
      {noreply,State#state{count=NewCount}}.

鉴于上面的代码,我想了解以下内容:
- 假设我输入 handle_cast 并向 gen_server 的 mailbox 发送适合 handle_info 情况的内容,handle_info 是否会在不同的线程上被调用就在此时此地( self() ! Message 而我还在评估 handle_cast?

事物展开的顺序是什么?

答案是 A。gen_server 的所有处理程序 - 如 handle_casthandle_info - 始终在同一个进程中执行。在 handle_cast 内发送给自己的消息将在 handle_cast 回调 returns 后由 gen_server 实现接收。只有这样 handle_info 才会被调用,并且 handle_info 会收到从 handle_cast.

返回的状态

通常,所有 gen_server 个处理程序总是按顺序调用,处理程序返回的状态传递给下一个调用的处理程序。

这里有一个例子可以证明 Wotek Surowka 的答案是正确的:

-module(s1).
-behavior(gen_server).
-compile(export_all).

start() ->
    gen_server:start_link(
      {local, ?MODULE}, 
      ?MODULE, 
      [],
      []
    ).

init(_Args) ->
    Count = 0,
    {ok, Count}.

handle_call(_Msg, _From, State) ->
    {reply, hello, State}.

handle_cast(_Msg, Count) ->
    io:format("Entered handle_cast()...~n"),

    self() ! hello,
    timer:sleep(10000), % Sleep for 10 seconds

    io:format("Returning from handle_cast()...~n"),
    {noreply, Count+1}.

handle_info(Msg, Count) ->
    io:format("Entered handle_info(), Msg= ~w~n", [Msg]),
    io:format("Count in handle_info() is: ~w~n", [Count]),
    io:format("Returning from handle_info()...~n"),
    {noreply, Count}.

go() ->
    spawn(
      fun() -> gen_server:cast(?MODULE, "some message") end
    ),
    ok.

在上面的示例中,handle_cast() 休眠了 10 秒,因此如果 handle_info() 异步执行,它在 handle_cast() 返回之前有足够的时间显示其输出。以下是 shell:

中的结果
~/erlang_programs/gen_s/1server$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3  (abort with ^G)

1> c(s1).     
s1.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,s1}

2> s1:start().
{ok,<0.71.0>}

3> s1:go().   
Entered handle_cast()...
ok  <--- return value of go()
Returning from handle_cast()...
Entered handle_info(), Msg= hello
Count in handle_info() is: 1
Returning from handle_info()...

4> 

输出显示 handle_info() 直到 handle_cast() returns.

之后才开始执行

而且,如果你添加一些打印语句来显示handle_cast()handle_info()里面的pid,你会看到pid是一样的:

-module(s1).
-behavior(gen_server).
-compile(export_all).

start() ->
    gen_server:start_link(
      {local, ?MODULE}, 
      ?MODULE, 
      [],
      []
    ).

init(_Args) ->
    Count = 0,
    {ok, Count}.

handle_call(_Msg, _From, State) ->
    {reply, hello, State}.

handle_cast(_Msg, Count) ->
    io:format("Entered handle_cast()...~n"),
    Self = self(),
    io:format("self() is: ~w~n", [Self]),

    Self ! hello,
    timer:sleep(10000), % Sleep for 10 seconds

    io:format("Returning from handle_cast()...~n"),
    {noreply, Count+1}.

handle_info(Msg, Count) ->
    io:format("Entered handle_info(), Msg= ~w~n", [Msg]),
    io:format("self() is: ~w~n", [self()]),
    io:format("Count in handle_info() is: ~w~n", [Count]),
    io:format("Returning from handle_info()...~n"),
    {noreply, Count}.

go() ->
    spawn(
      fun() -> gen_server:cast(?MODULE, "some message") end
    ),
    ok.

在shell:

1> c(s1).     
s1.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,s1}

2> s1:start().
{ok,<0.71.0>}

3> s1:go().   
Entered handle_cast()...
ok  <---return value of go()
self() is: <0.71.0>
Returning from handle_cast()...
Entered handle_info(), Msg= hello
self() is: <0.71.0>
Count in handle_info() is: 1
Returning from handle_info()...

4>