【转载】erlang 进程的 hibernate

简介:
简单的理解:   
  • hibernate 可以令处于 idle 状态的 erlang 进程马上进行 gc,因为进程处于 receive 状态下是不会 gc 的。
  • 在性能调优时发现,gc 对于消息发送速度的影响还是非常大的。

关于 erlang gc 问题也可以参看这个  
Recently, as part of RabbitMQ server development, we ran into an interesting issue regarding Erlang’s per-process garbage collection. If a process is idle — not doing any work at all, simply waiting for an external event — then its garbage-collector will not run until it starts working again. The solution is to hibernate idle processes, which causes a very aggressive garbage-collection run and puts the process into a suspended state, from which it will wake when a message next arrives.
所以查看 rabbitMQ 源代码可以看到里面的 gen_server/fsm 等进程统统都会使用 hibernate 。  

      下面解释下如何让进程 hibernate ,这里需要注意的是一个进程 hiberate 后,会清空 stack 栈,也就是说之前的调用关系全部没有了,也就是说hibernate 所在的函数永远不会返回,待有新消息时,进程从 hibernate(M,F,A) 里指定的 M:F 处开始运行。  

gen_server 和 gen_fsm 都提供了 hibernate 的方式:  

第一种:    在 gen_server 或 gen_fsm 回调接口返回时,指定 hibernate 。  
?
1
{next_state, NStateName, NStateData, Time1}
实际这个 Time1 可以指定为 hibernate,则重新回到 main loop 时会直接 hibernate 。  
这种方法可能使你的进程频繁 hibernate 又被唤醒,效率不是很好。  

正确的方式应该是,当你预期你的进程一段时间内不会收到消息才 hibernate 。  
所以推荐下面的方法,直接看下示例代码:  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
%% ====================================================================
%% Interface Function
%% ====================================================================
join (UserId)->
     io: format ( "join UserId=~p~n" ,[UserId]),
     gen_fsm:sync_send_event(?MODULE, { join ,UserId}).
 
start()->
     gen_fsm:send_event(?MODULE,start).
 
 
%% ====================================================================
%% Callback Function
%% ====================================================================
wait_player({ join ,UserId},_From, State) ->
     print_inner_data(State),
     put(p,get(p)+1),
     ets:insert(State #state.players,{p,UserId}),
     Count=State #state.count+1,
     if
         Count =:= 3 ->
             io: format ( "jump to next phrase -> start~n" ),
             {reply,next_phrase,wait_start,State,5000};
         true ->
             NewState=State #state{count=Count},
        {reply,stand_still,wait_player,NewState,5000}
     end.
wait_player(timeout,State)->
     io: format ( "timeout happened when wait_player,let's hibernate~n" ),
     proc_lib:hibernate(gen_fsm, enter_loop, [?MODULE, [], wait_player,State]).
 
 
wait_start(start,State)->
     print_inner_data(State),
     io: format ( "recv start event ~n" ),
     {next_state,wait_start,State,5000};
 
wait_start(timeout,State)->
     io: format ( "timeout happened when wait_start,let's hibernate~n" ),
     proc_lib:hibernate(gen_fsm, enter_loop, [?MODULE, [], wait_start,State]).
 
start_link()->
     gen_fsm:start_link({ local ,?MODULE}, ?MODULE, [] ,[]).
 
init([])->
     put(p,0),
     {ok,
         wait_player,
         #state
         {
             count=0,
             players=ets:new(players,[bag])
         },
         5000
     }.
 
print_inner_data(State)->
io: format ( "inner data: dict=~p,ets=~p~n" ,[get(p),ets:tab2list(State #state.players)]).
运行:   
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2> {ok,Pid}=fsm:start_link().
{ok,<0.39.0>}
3> process_info(Pid,total_heap_size).
{total_heap_size,233}
4> fsm: join (123).
join UserId=123
inner data: dict=0,ets=[]
stand_still
timeout happened when wait_player, let 's hibernate
5> process_info(Pid,total_heap_size).
{total_heap_size,33}
6> fsm: join (456).
join UserId=456
inner data: dict=1,ets=[{p,123}]
stand_still
      总体上,是让进程在 main_loop 里先 timeout ,也就是证明一段时间内都没有消息到达,然后 gen_fsm 进程是发送 {'gen_event',timeout} 消息处理 timeout 事件的,所以要在每个 Mod:StateName 处都加个处理 timeout 的分支,来进行 timeout 处理,也就是 hibernate 掉自己,重新进入的是 enter_loop 函数,这个东西很有用呐,大家可以查看源码,我就不多说了。  

另外,示例中可以看到,hibernate 会清空 stack,但是不会影响你的进程字典和 ets 等其它东西,可以放心用了。   
目录
相关文章
|
Linux Shell 网络安全
如何让Erlang服务器程序在后台运行,即实现守护进程的形态运行(★firecat推荐★)
如何让Erlang服务器程序在后台运行,即实现守护进程的形态运行(★firecat推荐★)
333 0
|
API
Erlang——直不断spawn新进程会有什么现象
前言 最近和同事聊天的时候,我突然想到进程Pid格式为,其中A1代表Node值, A2, A3则代表指定Node下的进程值,开始A3为0。当A2的值增加到一定数后, A3的值加1,那么问题来了: 1.
1305 0
|
Shell Perl 机器学习/深度学习
|
Web App开发
erlang的进程池。
转自: http://blog.sina.com.cn/s/blog_96b8a1540101542m.html   主要组成部分: https://github.com/devinus/poolboy https://github.
719 0
erlang 查看进程相关信息
出自: http://blog.sina.com.cn/s/blog_96b8a1540100zczz.html
725 0
|
网络协议
Erlang TCP Socket的接收进程的2种方案
转自:http://blog.csdn.net/summerhust/article/details/8740973   一旦打开了一个使用TCP连接的套接字,它就始终保持打开状态,直至任何一方关闭它或因为一个错误而终止。
1364 0
|
4月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
4月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
137 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)

相关实验场景

更多