从 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
?
事物展开的顺序是什么?
一个
handle_cast
进入
handle_cast
发到自己邮箱
handle_cast
returns
handle_info
被触发
B
handle_cast
进入
handle_cast
发到自己邮箱
3.handle_info
被触发(并发)并且可能改变状态
handle_cast
可能会或可能不会在 handle_info
完成之前结束,并且可以通过 handle_info
更改状态
答案是 A。gen_server
的所有处理程序 - 如 handle_cast
或 handle_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>
我有一个 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
?
事物展开的顺序是什么?
一个
handle_cast
进入handle_cast
发到自己邮箱handle_cast
returnshandle_info
被触发
B
handle_cast
进入handle_cast
发到自己邮箱
3.handle_info
被触发(并发)并且可能改变状态handle_cast
可能会或可能不会在handle_info
完成之前结束,并且可以通过handle_info
更改状态
答案是 A。gen_server
的所有处理程序 - 如 handle_cast
或 handle_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>