gen_server三两话

gen_server实现 阅读erlang gen_server源码,分析 阅读详情

 from:庆亮的博客 http://www.qingliangcn.com

gen_server是OTP中的一个重要组成,在开发中出现的频率相当高。弄明白这一块的,对于gen_server的使用有着相当好的帮忙。下面多数为代码。

从start_link开始:

gen_server.erl

start_link(Name, Mod, Args, Options) ->

gen:start(?MODULE, link, Name, Mod, Args, Options).

 

跳到gen.erl,这里的GenMod值为gen_server,LinkP为link

start(GenMod, LinkP, Name, Mod, Args, Options) ->

    case where(Name) of

undefined ->

    do_spawn(GenMod, LinkP, Name, Mod, Args, Options);

Pid ->

    {error, {already_started, Pid}}

end.

再跳:

do_spawn(GenMod, link, Name, Mod, Args, Options) ->

    Time = timeout(Options),

    proc_lib:start_link(?MODULE, init_it,

[GenMod, self(), self(), Name, Mod, Args, Options],

Time,

spawn_opts(Options));

跳到proc_lib.erl文件:

start_link(M,F,A,Timeout,SpawnOpts) when is_atom(M), is_atom(F), is_list(A) ->

    Pid = ?MODULE:spawn_opt(M, F, A, ensure_link(SpawnOpts)),

sync_wait(Pid, Timeout).

注意这里有个等待返回,之后需要proc_lib:init_ack来返回消息。

spawn_opt(M, F, A, Opts) when is_atom(M), is_atom(F), is_list(A) ->

    Parent = get_my_name(),

    Ancestors = get_ancestors(),

    check_for_monitor(Opts),

    erlang:spawn_opt(?MODULE, init_p, [Parent,Ancestors,M,F,A], Opts).

这里调用proc_lib模块的init_p方法:

-spec init_p(pid(), [pid()], function()) -> term().

init_p(Parent, Ancestors, Fun) when is_function(Fun) ->

    put('$ancestors', [Parent|Ancestors]),

    {module,Mod} = erlang:fun_info(Fun, module),

    {name,Name} = erlang:fun_info(Fun, name),

    {arity,Arity} = erlang:fun_info(Fun, arity),

    put('$initial_call', {Mod,Name,Arity}),

    try

Fun()

    catch

Class:Reason ->

    exit_p(Class, Reason)

    end.

-spec init_p(pid(), [pid()], atom(), atom(), [term()]) -> term().

init_p(Parent, Ancestors, M, F, A) when is_atom(M), is_atom(F), is_list(A) ->

    put('$ancestors', [Parent|Ancestors]),

    put('$initial_call', trans_init(M, F, A)),

    init_p_do_apply(M, F, A).

init_p_do_apply(M, F, A) ->

    try

apply(M, F, A) 

    catch

Class:Reason ->

    exit_p(Class, Reason)

end.

有点晕头了吧,MFA是什么呢?如下:

gen, init_it,

[gen_server, self(), self(), Name, Mod, Args, Options]

这里的Name, Mod, Args是我们自己的注册名,模块名、参数。

调回init:

init_it(GenMod, Starter, Parent, Name, Mod, Args, Options) ->

    case name_register(Name) of

true ->

    init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options);

{false, Pid} ->

    proc_lib:init_ack(Starter, {error, {already_started, Pid}})

    end.

init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options) ->

    GenMod:init_it(Starter, Parent, Name, Mod, Args, Options).

ok,又回到gen_server了。跳转到gen_server的init_it:

init_it(Starter, self, Name, Mod, Args, Options) ->

    init_it(Starter, self(), Name, Mod, Args, Options);

init_it(Starter, Parent, Name0, Mod, Args, Options) ->

    Name = name(Name0),

    Debug = debug_options(Name, Options),

    case catch Mod:init(Args) of

{ok, State} ->

    proc_lib:init_ack(Starter, {ok, self()}),      

    loop(Parent, Name, State, Mod, infinity, Debug);

{ok, State, Timeout} ->

    proc_lib:init_ack(Starter, {ok, self()}),      

    loop(Parent, Name, State, Mod, Timeout, Debug);

{stop, Reason} ->

    %% For consistency, we must make sure that the

    %% registered name (if any) is unregistered before

    %% the parent process is notified about the failure.

    %% (Otherwise, the parent process could get

    %% an 'already_started' error if it immediately

    %% tried starting the process again.)

    unregister_name(Name0),

    proc_lib:init_ack(Starter, {error, Reason}),

    exit(Reason);

ignore ->

    unregister_name(Name0),

    proc_lib:init_ack(Starter, ignore),

    exit(normal);

{'EXIT', Reason} ->

    unregister_name(Name0),

    proc_lib:init_ack(Starter, {error, Reason}),

    exit(Reason);

Else ->

    Error = {bad_return_value, Else},

    proc_lib:init_ack(Starter, {error, Error}),

    exit(Error)

end.

呵呵,苦尽甘来,终于来到loop主循环了。 gen_server的消息怎么来的?就是这个loop不断地取出消息、decode_msg、再loop来不断从消息队列中取出消息的。这个主循环就是我们的gen_server进程了。

loop(Parent, Name, State, Mod, hibernate, Debug) ->

    proc_lib:hibernate(?MODULE,wake_hib,[Parent, Name, State, Mod, Debug]);

loop(Parent, Name, State, Mod, Time, Debug) ->

    Msg = receive

      Input ->

    Input

  after Time ->

  timeout

  end,

    decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, false).

decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->

    case Msg of

{system, From, Req} ->

    sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,

  [Name, State, Mod, Time], Hib);

{'EXIT', Parent, Reason} ->

    terminate(Reason, Name, Msg, Mod, State, Debug);

_Msg when Debug =:= [] ->

    handle_msg(Msg, Parent, Name, State, Mod);

_Msg ->

    Debug1 = sys:handle_debug(Debug, {?MODULE, print_event}, 

      Name, {in, Msg}),

    handle_msg(Msg, Parent, Name, State, Mod, Debug1)

    end.

这里我们就看到了terminate的自动回调(如果设置了trap_exit)。

handle_msg中处理了handle_call类型的调用, 而handle_cast和handle_info则由dispatch来处理:

dispatch({'$gen_cast', Msg}, Mod, State) ->

    Mod:handle_cast(Msg, State);

dispatch(Info, Mod, State) ->

Mod:handle_info(Info, State).

handle_msg处理handle_call也很简单,回调我们的handle_call方法:

handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, Debug) ->

case catch Mod:handle_call(Msg, From, State) of

……

至此,整个gen_server的运行流程就清楚了(晕的话,多看几遍)。

回头再来看看terminate的处理

terminate(Reason, Name, Msg, Mod, State, Debug) ->

    case catch Mod:terminate(Reason, State) of

{'EXIT', R} ->

    error_info(R, Name, Msg, State, Debug),

    exit(R);

_ ->

    case Reason of

normal ->

    exit(normal);

shutdown ->

    exit(shutdown);

{shutdown,_}=Shutdown ->

    exit(Shutdown);

_ ->

    error_info(Reason, Name, Msg, State, Debug),

    exit(Reason)

    end

end.

这里terminate在回调了gen_server的terminate函数后,又exit了一次,目的是为了产生一个'EXIT'消息给supervisor,以便让supervisor做相应的重启策略。

 

erlang gen_server 对gen_server的函数只是浏览了下,没仔细看过,这里写一下几个重要函数的参数和返回值 call(ServerRef, Request, Timeout) -> Reply 向ServerRef发起一个call的请求直到回调模块调用Module:handle_call完成该请求并返回或者超时。 ServerRef就是pid,name等等,这里面有个需要注意的参数Timeout,默认值为5... 阅读详情

相关推荐

Erlang:RabbitMQ源码分析 2. gen_server和gen_server2 深入剖析

RabbitMQ重新实现了erlang的gen_server -> gen_server2。 本文从源码角度对比二者的实现。

liaosongbo的专栏 3108

[Erlang] - gen_server

gen_server.erl (上面的spawn经过fun的传来传去最后会来到gen_server)proc_lib.erl是一个关于进程的工具类,提供了同步启动进程的机制。

偶尔来看看 895

HP DL388 GEN10 U启动安装windows server 2012 R2

HP DL388 GEN10 U启动安装windows server 2012 R2 ① 准备1-2个U盘(其中一个须大于等于8G),并格式化为FAT32格式 ② 使用UltraISO或其他写盘软件将系统镜像写入U盘中 文件-打开-打开镜像文件 启动-写入硬盘镜像 在弹出的窗口中选择正确的U盘-点击写入并等待写入完成 将厂商提供的RAID驱动 复制进U盘根目录 ③ 将U盘插在服务器后置USB接口(插在前置接口会出现不识别、无法引导等问题),并对服务器上电启动 ④ 在自检阶段按下F11,保证F11 Bo

weixin_43833900的博客 1万+

ETS 和 gen_server 的使用

ETS和DETS表保存的是元组。元组里的某一个元素(默认是第一个)被称为该表的键。通过键来向表里插入和提取元组。当我们向表里插入一个元组时会发生什么,取决于表的类型和键的值。一些表被称为set,它们要求表里。另一些被称为同键表bag,它们允许。ets有4种类型的table,如表所示:基本的表类型(异键表和同键表)各有两个变种,它们共同构成四种表类型:异键、有序异键(ordered set)、同键和副本同键(在异键表里,各个元组里的键都必须是独一 无二的。

qq_53795917的博客 288

gen_server 和 gen_fsm 的区别和应用

在 Erlang 编程语言中,gen_server 和 gen_fsm 是两个重要的 OTP(Open Telecom Platform)设计模式,用于构建可扩展和可靠的并发应用程序。本文将详细介绍 gen_server 和 gen_fsm 的区别和应用,并提供相应的源代码示例。gen_server 适用于处理并发请求和维护内部状态的场景,而 gen_fsm 适用于实现有限状态机模型的场景。状态转换:gen_server 的状态转换是由客户端请求触发的,而 gen_fsm 的状态转换是由事件驱动的。

AzProcessgroup的博客 272

erlang初涉及8_gen_server入门

gen_server代表的就是“行为模式”的一种,行为模式的目的在于为特定类型的进程提供一套模板。类似的还有supervisor监督者,application应用程序等

Nicer_feng's blog 388

erlang学习笔记之gen_server 入门

以下三点是编写gen_server回调模块的简要步骤:(1) 确定回调模块名。(2) 编写接口函数。(3) 在回调模块里编写六个必需的回调函数。

keyzx的博客 181

Python实战:3分钟搞定A股K线数据抓取(附东方财富/腾讯API完整代码)

本文为量化交易初学者提供了一份快速获取A股K线数据的实战指南。通过对比东方财富与腾讯财经两大免费API的优劣,并附上可直接运行的完整Python代码,帮助读者在3分钟内搭建起自己的数据抓取管道,为构建量化交易系统奠定坚实的数据基础。

weixin_29062255的博客 2909

gen_server

文章目录gen_server1、gen_server起步1.1、第一步:确定回调模块的名称1.2、第二步:写接口函数1.3、第三步:编写回调函数2、gen_server回调的结构2.1、启动服务器时发生了什么2.2、调用服务器程序时发生了什么2.3、调用和通知2.4、发送给服务器的原生消息2.5、HastalaVista,Baby(服务器的终止)2.6、热代码替换3、gen_server详解3.1、启动服务器3.2、调用服务3.3、停止服务器3.4、代码更新 gen_server 1、gen_server起

rwxxtt的博客 867

HOPE:基于强化学习的混合策略路径规划器,适用于多样化停车场景

本文提出了一种混合策略路径规划器(HOPE),用于解决自动停车中的路径规划问题。HOPE结合了强化学习(RL)和Reeds-Shepp(RS)曲线,通过动作掩码机制引导RL智能体的探索,并利用Transformer融合环境感知信息与掩码。该方法在多样且复杂的停车场景中实现了超过97%的成功率,并通过真实实验验证了其泛化能力。此外,本文还提出了基于空间与障碍物分布的停车场景难度分级标准,进一步提升了训练与评估的效率。实验结果表明,HOPE在规划成功率和跨场景泛化能力上均优于传统的基于规则算法和朴素强化学习方法

weixin_42783201的博客 1466

python等级考试——一级知识点汇总(不包含turtle画图)

本篇文章是针对中国电子学会青少年编程等级考试的,适合初学者以及青少年编程学习者

weixin_65350557的博客 9026

Erlang 源码分析之 Gen_Server

众所周知 Erlang/OTP 是一个具有高并发、低延时、高容错等特性的平台。 其三大 Behaviour : Gen_ Server(客户端服务器); Gen_ Fsm(有限状态机); Gen_ Event(事件通知),是其坚如磐石的系统的基石。 本场 Chat 将透过源码分析其中 Gen_Server 的实现原理并管中一窥 Erlang 的设计思想。 本场 Chat 主...

GitChat 1254

AI训练师三级考证避坑指南|假证辨别+机构套路+OSTA验证

这是最基础的问题,也是最容易忽略的问题。人工智能训练师三级证书本身是有价值的——政府认可的职业技能等级证书、多地紧缺工种补贴、人才引进加分。但正因为有价值,才引来了大量骗子。记住三句话OSTA查不到的证,一分钱都不值声称免考包过的,100%是骗子培训费一次性谈清楚,后续加价直接走人如果你正在考虑考人工智能训练师三级证书,想要从报名到备考到拿证的完整一站式指南,欢迎查看我的付费专栏:📖《人工智能训练师三级·从零到拿证完全指南》99篇系统化内容,覆盖报名、备考、冲刺、拿证全流程。

白话机器学习 1219

Erlang如何查看gen_server内部的状态

方法1、自写个函数,想gen_server发查看的消息。 方法2、利用系统现有的架构。sasl应用带了一个si的东西 全名是status inspector, 这个东西就是设计来帮用户解决这个问题的。 %%%------------------------------------------------------------------- %%% @author flybird %%% @

wangyangkobe的专栏 2022

【Bug已解决】Codex CLI 运行时出现 command not found: codex 解决方案

方案适用场景推荐指数修复 PATH 配置最常见的基础排查方向⭐⭐⭐⭐⭐检查原生二进制完整性PATH 正常但执行仍然异常⭐⭐⭐⭐统一包管理器混用多种包管理器导致混乱⭐⭐⭐⭐确认安装脚本未被跳过CI/CD 或企业策略环境⭐⭐⭐⭐排查网络下载渠道企业内网/受限网络环境⭐⭐⭐需要留意 warning 中是否涉及脚本执行失败、网络超时重试等信息,这类 warning 往往是后续问题的前兆,建议出现明显的下载/网络相关警告时就主动重新安装一次确认。Codex CLI 报。

一键难忘的博客 1万+

迟滞电压比较器电路的原理与计算

迟滞电压比较器是一种具有双阈值特性的电路,通过正反馈机制实现抗噪声干扰功能。文章详细分析了其工作原理,包括同相型和反相型两种结构的电压阈值计算与电阻设计方法,并提供了已知门限求电阻和已知电阻求门限的推导公式。工程应用中需注意输出类型匹配、电阻取值范围、噪声裕量设计等问题。该比较器在信号处理、波形转换等场景中具有重要应用价值,设计时需综合考虑供电电压、参考电压和噪声特性等因素。

硬核科技 2679

erlang中gen_server/gen_fsm使用hibernate

简单的理解:  hibernate可以使你闲置的erlang进程马上进行gc,因为进程处于receive状态下是不会gc的  我在性能调优时发现,gc对于消息发送速度的影响还是非常大的  关于erlang gc问题也可以参看这个  引用 Recently, as part of RabbitMQ server development, we ran into an i

oklizy的专栏 1832

SolidWorks 小车底盘 装配体

通过制作小车底盘了解solidworks装配体的部分知识

及时总结 2226

gen_server模块

Erlang资料资料整理 在《Programming Erlang》的OTP introduction章节中,作者通过循序渐进的方式,向我们展示了gen_server设计思路,现在做下总结:  在具体看gen_server之前,我们先看一个server通用框架:  在这个server里,你几乎看不到任何和具体功能相关的东西,它只提供了一个server所具备的基本框架,那它是如何运

_magicaljobs的专栏 902

iOS逆向之深入解析Hook的原理方法和安全防护

Hook简介 Hook就是一种改变程序执行流程的一种技术的统称; 一段程序的执行流程是 A --> B --> C,现在我们在 A 和 B 之间插入一段代码或者直接改变 B ,这样程序原有的执行流程就发生了改变。如下图所示: Hook的方式:Method Swizzle,fishhook,Cydia Substrate; Hook原理 一、Method Swizzle 原理 利用OC的Runtime特性,动态去改变SEL(方法编号)和IMP(方法实现)的对应关系,达到OC方法调用流程改变

╰つ栺尖篴夢ゞ 2万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

gen_server 和 gen_fsm 的区别和应用--erlang

erlang 里 gen_server 与gen_fsm 的异同 深入的思考和了解可以提升自己对编程的理解

little 小样 709

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

用超时来实现gen_server的定时

-module(otp_test). -behaviour(gen_server). -export([start_link/0]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). st

Sunface撩技术 2162

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

erlang gen_fsm/gen_event/gen_server/gen_tcp

gen_fsm: 参考资料 LYSEGG gen_fsm的例子 Erlang OTP设计原则Gen_Fsm行为 相关博客gen_fsm gen_event: 参考资料 LYSEGG [解释加例子]http://erlangdisplay.iteye.com/blog/315391 gen_event 解释 例子 erlang behaviour gen_event gen_server:...

dianboju4932的博客 209

Gen8服务器系统安装,gen8,初装windows server 2008 r2

本帖最后由 采花郎 于 2015-1-7 15:35 编辑1,事先温习过各位前辈的发帖,决定把系统安装在SATA5上,这样把系统和数据分开,互不影响2,ESXi折腾不来,没那么高的水平,win server 2008已经有点折腾人了3,用winntsetup装win8,失败了多次,最后才明白,要设置硬盘为AHCI模式,才能正常启动pe不蓝屏,要设置TF卡第一启动方式(BIOS里面的叫法是SD卡),...

weixin_34043312的博客 5518
上一篇: erlang网络编程的几个性能调优和注意点
下一篇: Erlang开发建议
jamesjun
博客等级 码龄19年 25粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值