【转载】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 等其它东西,可以放心用了。  

时间: 2024-11-08 22:18:04

【转载】erlang 进程的 hibernate的相关文章

Erlang 进程创建性能测试

测试代码来自 Progremming Erlang. Erlang: R13B (erts-5.7.1), 启动参数 +P 5000000 系统: Window XP CPU: E8200 2.66G 双核 内存: 4G Erlang R13B (erts-5.7.1) [smp:2:2] [rq:2] [async-threads:0] Eshell V5.7.1  (abort with ^G) 1> c(processes). {ok,processes} 2> processes:ma

【转载】关于 Erlang 和 SMP 的一些说明

以下是一些关于 Erlang SMP 实现细节.性能.伸缩性相关一些简单介绍.  -=-=-=-=-=-        几周之内还有一个关于多核如何运作以及未来如何发展的更详细的介绍.我打算将一些内容放在我的报告中,将于 9 月 27 日的 ICFP2008,Erlang Workshop 在 Victoria BC 展示给大家.       没有 SMP 支持的 Erlang VM 只有 1 个运行在主处理线程中的调度器.该调度器从运行队列(run-queue)中取出可以运行的 Erlang

Scala和Erlang,以及多核主导的未来

问题描述 未来注定是多核的世界,问题在于如何去解决多核的危机.Scala和Erlang是两门渴望成为其解决方案的语言,但它们也有些许的不同.那么它们所采取的方式各有什么利弊呢?引入问题摩尔定律已经改变了.我们不再获得和以前一样的时钟频率增长,取而代之,我们得到了更多的(CPU)核心.今天,也许你的笔记本都已经是双核的了.为了利用多核的特性,应用程序需要支持并发.如果你的客户买了一台八核的机器,要向他们解释清楚正常情况下应用程序只会用到12%的CPU能力将是一件费时费力的事,即便该机器是为该应用量

【原创】Erlang 之 erl_crash.dump 生成

-=-=-=-=- 我是<我是歌手 >的分隔线 -=-=-=-=-  (以下为原文引用)        crashdump 对于 erlang 的系统来讲如同 core 对于 c/c++ 程序一样宝贵,对于系统问题的修复提供了最详细的资料.当然 erlang 很贴心了提供了网页版的 crashdump_view 帮助用户解读数据,使用方法如下: crashdump_viewer:start().       因为 crashdump 文本文件里面记录了大量系统相关的信息,这些信息对于分析系统的

【原创】Erlang 之 heart 功能

      我们写的程序不可能都没有 bug ,都存在 crash 的危险.很多时候我们需要个看门狗(watchdog)程序,在发现系统不正常的时候,就把系统重新启动.这类 watchdog 程序从内核到各种高可用程序都会设置有一个.erlang 系统当然不能免俗,也有个 heart .  我们来看下流程和效果:  $ export HEART_COMMAND="erl -heart" $ erl -heart heart_beat_kill_pid = 12640 Erlang R1

【原创】Erlang 之 entop 使用问题

   工欲善其事,必先利其器.排查 erlang 系统问题时,肯定希望能有一个像 Unix top 一样的工具,entop 就是这么个东东.  ---------- 我是三月份发版本天天加班的分隔线 -----------  (以下内容翻译自 entop 的 README.md 文件)  entop  如同 Unix 中 top 一样的 Erlang 节点信息查看工具.  简介       entop 是用来展示远端 Erlang 节点运行信息的工具,其信息显示的方式类似于 Unix 中的 to

Erlang是未来用于并发性的Java?

问题描述 未来的计算是并发计算.现今甚至桌面CPU也是多核的,当客户给他们的服务器购买了越来越多的CPU时,他们期望其应用伸缩自如以利用他们的新投资.但是今天的许多软件系统并不能做到这一点.处理并发计算是件困难的事情.但是在普遍使用的编程语言中,并发机制与同一语言的许多其他抽象相比是低层机制,对解决这一问题没有帮助.处理并发性需要做许多工作,但是有使其更简单的方法.Ralph Johnson 撰写了一篇关于 Erlang 将成为 下一个Java的博文.Erlang进程间通讯的视角完全不同,而且R

Erlang初学:Erlang的一些特点和个人理解总结_Erlang

我对 Erlang 编程理念的理解:以分布式架构师的角度写代码. 函数式编程 Erlang 里面的函数是数学里面的函数:必须有返回值. 只要是函数必然有返回值,函数是一个过程,以英文的句号为函数结束符. 函数结束之前的表达式就是该函数的返回值. 所以这也是在 Erlang 里面的函数不会看到任何 return 语句的原因. C++ 等其他语言的函数和函数之前可以通过共享变量来实现消息传递. Erlang 里面的函数不可以,消息的传递通过函数的传入和传出. 也只是为什么 Erlang 号称天生之处

开源Erlang真的能成为下一代Java语言吗?

问题描述 一.高可**性的Erlang,有望取代JavaErlang将成为一个非常重要的语言.它也许就是下一代的Java语言.目前Erlang发展的主要问题就在于没有一个大的公司来支持它,作为它强大的后盾.结果,Erlang被推动成为一个开源的项目.Erlang语言最大优势就是它非常适合多核,web服务的特点.事实上,Erlang是唯一成熟的,非常稳定可**,适合开发运行在多核机器上的高伸缩性的系统.Erlang最为并行的Prolog,始于20年前.Joe Armstrong发明了它,并成为推动