• gen_server2 与gen_server的对比


    在erlang杀手级应用rabbitmq中,不难发现,有一个gen_server2.erl模块。而在rabbitmq中,gen_server2.erl是对gen_server.erl模块的重写。

    RabbitMQ重新实现了gen_server -> gen_server2。 很多Module都是用了这个behavior。

    我们首先来看下OTP里gen_server 的实现:

    gen_server的启动入口是gen_server:start_link,一个以gen_server为behavior的Module,例如frontend call gen_server:start_link( node_manager)来启动node_manager这个gen_server.

    gen_server:start_link启动一个进程,执行gen_server:init_it。

    gen_server:init_it做了三件事:

    1.  调用node_manager:init

    2.  send ack to frontend 

    3.  start loop

    loop

    先比较gen_server和gen_server2的loop

    gen_server loop是receive一个message,处理这个message,再去receive下一个message,没有message时就block在那里。

    message一般是三种来源:

    1. frontend 的gen_server:call 由 node_manager: handle_call来处理, 会有reply send to frontend

    2. frontend 的gen_server:cast 有 node_manager : handle_cast来处理

    3.  其他由 node_manager : handle_info来处理

    而gen_server2的loop与其不同:

    1. receive所有message, 加到Queue里。

    2. 如果Queue不空,从Queue里取出一个处理,再step1

    3. 如果Queue为空:

    3.1 如果没有hibernate, 直接去receive,然后加到Queue。如果timeout, 就由handle_info来处理

    3.2 如果有hibernate,没有backoff, 将timeout设成 infinity, 在那一直去receive(边睡边等)

    3.3 如果有hibernate,也有backoff, 直接去receive,然后加到Queue,如果timeout,去call pre_hibernate, hibernate,wake 以后重新调整timeout。

    gen_server的message box可能非常大,而gen_server2使用了一个额外的Queue来解决这个问题,注释显示这样避免了selective receives in callbacks 去scan一个巨大的MessageBox, selective receives in callbacks例如multi_call,mcall

    hibernate 

    node_manager的init和所有callback function 都可以返回一个hibernate,使loop进入休眠,直到有下个message进来。进入休眠会比较省cpu资源,一般对于下一个message需要很久后才come in的scenario

    gen_server2提供了两个新的callback function: pre_hibernate and post_hibernate。

    这里看下gen_server和gen_server2的 hibernate实现:

    gen_server的每轮loop一旦收到一个hibernate, 就立刻调用proc_lib:hibernate, 当醒来时直接receive,然后处理message。

    gen_server2的每轮loop一旦收到一个hibernate,先调用pre_hibernate ,再调用proc_lib:hibernate,醒来时receive所有message, 加到Queue里,再调用post_hibernate,然后处理Queue里的message

    timeout

    gen_server和gen_server2里的timeout不太一样

    gen_server里,timeout是针对一个request处理,node_manager的init, handle_call, handle_cast, handle_info都可以返回一个timeout,  这样当下一次 receive timeout了以后,由handle_info(timeout)来处理。如果不设timeout, 默认是infinity,就是receive会block在那里。gen_server的timeout和hibernate没有什么关系,当有hibernate时就没有timeout,因为直到有request来才会wake, 这样就直接receive即可。

    gen_server2里,timeout是在Queue空的时候使用,Queue空的时候需要receive messages,此时有三种情况:

    1. 没有hibernate,就和gen_server一样,如果timeout由handle_info处理

    2. 有hibernate没有backoff, timeout就没用了,跟gen_server一样,直接进入hibernate。

    3. 当有hibernate又有backoff时,receive会等待timeout的时间再进入hibernate,而timeout时间是不断调整的。

    backoff

    gen_server2 的backoff 有这个几个参数:InitialTimeout, MinimumTimeout, DesiredHibernatePeriod。当一次hibernate的时间很长,超过DesiredHibernatePeriod,就会将下次timeout设置的时间短一点,这样可以尽快hibernate;如果当一次hibernate的时间很短,就会将下次timeout设置的时间长一点,这样在request来的很频繁的时候避免去hibernate。

    mcall

    gen_server2 增加了一个mcall接口,可以一次并行call gen_server2 

  • 相关阅读:
    线程池示例(摘抄)
    Visual Studio 相关
    Linq 内连接和外连接(转载)
    asp.net mvc4 简单使用Autofac依赖注入小结
    jquery加载解析XML文件
    权限验证AuthorizeAttribute
    常用SQL Server规范集锦及优化
    linq to datatable 和lambda查询datatable
    ASP.NET 大文件下载的实现思路及代码
    分页存储过程
  • 原文地址:https://www.cnblogs.com/unqiang/p/9517925.html
Copyright © 2020-2023  润新知