最近觉得实在是该梳理梳理erlang的框架内容了,所以整理了下。

OTP(开放电信平台):并发系统平台,
特点:容错(erlang:get_stacktrace(),try-catch,trap_exit进程退出时候发送信息{'Exit',Pid,Reason},不会所有进程都崩溃而且可以由supervisor重启)--链路来容错、
监督(supervisor,重启机制)、
可升级(code_change(gen_server))、
并发(spawn,消息(而非java|c的锁))--进程&消息传递进行并发编程、
分布(nodes(),可以分布到多台机器上 erl-sname ...,rpc).
OTP目的:在于构建稳定、容错的系统。
appication:erlang对相关模块进行打包的一种手段。将这些模块做为一个整体。应用有自己的
生命周期:启动,完成任务,最后关闭。部分应用可以同时运行多个实例,另一些仅限一个。
supervisor:OTP最为重要的特性。监控其他进程,并在出现问题的时候重启故障,并向上汇报出现的问题。
还可以将监督者组织成监督树(更可靠)
-------------------------------------------------------------------------------------------
1.OTP的组织形式:
『1』遵循标准目录结构;
『2』添加用于存放应用元数据的.app文件
『3』创建一个application行为模式下实现模块,负责启动应用。
另外,应用行为模式中的start/2启动根监督者,实现supervisor行为模式的进程--统一派生和管理。
applicationName.app {application,Appliaction,[{description},{modules,[]},{mod,Start}...]}(application API 中有)
application_app.erl(behavior(application))
application_sup.erl(behavior(supervisor))
application_element.erl(具体处理问题的模块)
application_store.erl(用于存储oracle,or cache(redis))
-------------------------------------------------------------------------------------------
2.应用行为模式:
-module(application_app).
-behavior(application).
-export([start/2,
stop/1]).
start(_Type,_StartArgs)->
application_store:init(),
case application_sup:start_link() of
{ok,Pid}->
{ok,Pid};
Other ->
{error,Other}
end.
stop(_State)->
ok.
application两件事:初始化store及sup
-------------------------------------------------------------------------------------------
3.实现监控
-module(application_sup).
-behavior(supervisor).
-export([
start_link/0,
start_child/1 %%动态启动子进程
]).
-export([init/1]).

start_link()->
supervisor:start_link({local,?MODULE},?MODULE,[]).
%%{ok,State}.supervisor的是start_link的三个参数,第一个是:让OTP库在本地节点上以
MODULE为注册名自动注册监控进程。第三个参数给init的参数。

start_child(ChildSpec)->
supervisor:start_child(?MODULE,ChildSpec).

start_child(Value,LeaseTime)->
supervisor:start_child(?MODULE,[Value,LeaseTime]).
%%start_child(SupRef, ChildSpec) -> Result ChildSpec = child_spec() | [term()] Result = {ok,Child} | {ok,Child,Info} | {error,Error}
%% 生成子进程不一定都要childspec的六个参数,如果没有启动方式是simple_one_for_one就可以不定义这么多参数,而是像这个子进程,可以在后面将子进程需要的参数放入。
ChildSpec should be a valid child specification (unless the supervisor is a simple_one_for_one supervisor, see below). The child process will be started by using the start function as defined in the child specification.
If the case of a simple_one_for_one supervisor, the child specification defined in Module:init/1 will be used and ChildSpec should instead be an arbitrary list of terms List. The child process will then be started by appending List to the existing start function arguments, i.e. by calling apply(M, F, A++List) where {M,F,A} is the start function defined in the child specification.
init()->
Server ={application_server,{application_server,start_link,[]},temporary,brutal_kill,worker,[application_server]}, %%6个参数
Children = [Server],
RestartStrategy = {simple_one_for_one,0,1},
{ok,{RestartStrategy,Children}}.

RestartStrategy:{How,MaxCounts,TimeWithin}
ChildrenSpec:{ID,start{M,F,A},restart,shutdown,type,modules}
Restart:permanent总是重启|temporary永不重启|transient只有进程意外终止时重启
shutdown:指明如何终止进程,2000表示软关闭策略,留的自我了断时间,如果未在指定时间自行退出,则将被无条件终止。
brutal_kill:关闭监控进程时立即终止进程。
infinity:主要用于子进程本身也是监控进程,给予进程充分时间自行退出。
type:supervisor|worker
modules:该进程所以依赖的模块。
-------------------------------------------------------------------------------------------
-module(application_server).
-behavior(gen_server).
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3
]).
-export([
start_link/2,
create/1,
create/2,
fetch/1,
replace/2,
delete/1]).

-record(state,{value,lease_time,start_time}).
-define(DEFAULT_LEASE_TIME,60*60*24).
%%五个基本方法用于实现,没有调用gen_server,而是gen_server的对应方法调用它们,所以参数是固定的。返回参数个数不是固定的。
init([Value,LeaseTime])->
Now = calendar:local_time(),
StartTime = calendar:datetime_to_gregorian_seconds(Now),
{ok,#state{value = Value,lease_time = LeaseTime,start_time = time_left(StartTime,LeaseTime)}}.
time_left(_StartTime,infinity)->
infinity;
time_left(_StartTime,LeaseTime)->
Now = calendar:local_time(),
CurrentTime = calendar:datetime_to_gregorian_seconds(Now),
TimeElapse = CurrentTime - StartTime,
case LeaseTime - TimeElapse of
Time when Time =< 0 -> 0;
Time -> Time * 1000
end.
handle_call(fetch,_From,State)->
#state{value = Value,lease_time = LeaseTime,start_time = StartTime} = State,
TimeLeft =time_left(StartTime,LeaseTime),
{reply,{ok,Value},State,TimeLeft}.
handle_cast({replace,Value},State)->
#state{value=Value,lease_time=LeaseTime,start_time=StartTime}=State,
{noreply,State}. %%noreply服务器不用发送任何应答继续运行就好
handle_call(delete,State)->
{stop,normal,State}.
%%stop,会导致gen_server自行终止,终止原因为normal,通知OTP系统服务器为正常关闭。除非进程为permanet负责不进行重启。application_sup中init定义的为temporary所以不会重启。
handle_info(timeout,State)->
{stop,normal,State}.
terminate(_Reason,_State)->
application_store:delete(self()), %%ets表中删除pid为自己的进程
ok.
%%gen_server关闭时,会调用terminate回调来执行一些清理操作,需要抹除与进程相关的键。键和pid的映射关系维护在appliction_store中,所以也要手动删除。
code_change(_OldVsn,State,_Extra)->
{ok,State}.
%%以下方法调用gen_server, 方法的参数不固定,只要给gen_server的对应方法对应参数即可,写的时候看下实现的方法handle的参数有无以及怎么写的
start_link(Value,LeaseTime)->
gen_server:start_link(?MODULE,[Value,LeaseTime],[]).
create(Value,LeaseTime)->
application_sup:start_child(Value,LeaseTime). %%supervisor的start_child(SupRef, ChildSpec) -> Result

create(Value)->
create(Value,?DEFAULT_LEASE_TIME).
fetch(Pid)->
gen_server:call(Pid,fetch).
replace(Pid,Value)->
gen_server:cast(Pid,{replace,Value}).
delete(Pid)->
gen_server:cast(Pid,delete).
---------------------------
-module().
-behavior(gen_server).
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3
]).
-record(state,{}).
init([])->
{ok,#state{}}. %%完成初始化
handle_call(_Request,_From,State)->
Reply = ok,
{reply,Reply,State}.
handle_cast(_Msg,State)->
{noreply,State}.
handle_info(_Info,State)->
{noreply,State}.
terminate(_Reason,_State)->
ok.
code_change(_OldVsn,State,_Extra)->
{ok,State}.
------------------------
------------------------
gen_server module Callback module
----------------- ---------------
gen_server:start_link -----> Module:init/1

gen_server:call
gen_server:multi_call -----> Module:handle_call/3

gen_server:cast
gen_server:abcast -----> Module:handle_cast/2

- -----> Module:handle_info/2

- -----> Module:terminate/2

- -----> Module:code_change/3
gen_server的
1. start_link(Module, Args, Options) -> Result
start_link(ServerName, Module, Args, Options) -> Result
2. call(ServerRef, Request) -> Reply
call(ServerRef, Request, Timeout) -> Reply %%ServerRef = Name | {Name,Node} | {global,GlobalName} | pid()
3. cast(ServerRef, Request) -> ok
-------------------------------------------------------------------------------------------
3.缓存系统的基本功能:
缓存的启动和停止;向缓存中添加(key-value),查询,更新,删除
API::
-module(application_store).
-export([
init/0,
insert/2,%% 同update,因为ets表中id唯一,如果后一个与前面的key相同,值自动覆盖
delete/1,
select/1
]).
-define(TABLE_ID,?MODULE).
init()->
ets:new(?TABLE_ID,[public,named_table]).
insert(Key,Pid)->
ets:insert(?TABLE_ID,{Key,Pid}).
select(Key)->
case ets:lookup(?TABLE_ID,Key) of
[{Key,Pid}]-> {ok,Pid};
[] -> {error,not_found}
end.
delete(Pid)->
ets:match_delete(?TABLE_ID,{'_',Pid}). %%'_'匹配所有的值,{}内必须是全匹配;ets表中可以存入,key,value,value多个,不一定是键值对,而是键值值值...
---------------------------------
ets表的基本操作 (ets中key值唯一)
3> ets:new(aa,[public,named_table]). aa
4> ets:insert(aa,{key,value}). true
5> ets:lookup(aa,key). [{key,value}]
6> ets:insert(aa,{key,value1}). true
7> ets:lookup(aa,key). [{key,value1}]
32> ets:insert(aa,{value2,key,dd}). true
33> ets:lookup(aa,key). [{key,value1,dd}]
34> ets:match_delete(aa,{'_',key,'_'}). true
35> ets:lookup(aa,value2). []
6> ets:insert(aa,{value2,key,aa}). true
37> ets:lookup(aa,value2). [{value2,key,aa}]
38> ets:match_delete(aa,{'_',key}). true
39> ets:lookup(aa,value2). [{value2,key,aa}]

delete(Tab) -> true 表删除
delete(Tab, Key) -> true 删除内容(根据key删除)
match_delete(Tab, Pattern) -> true 模式匹配删除(根据value删除)
------------------------------------------------------------------------------------
4.
-_module(first_cache).
-export([
insert/2,
lookup/1,
delete/1]).
insert(Key,Value)->
case application_store:select(Key) of %%查看ets表中是否有,如果有就是key已经放入,将value更新到#state{}中
{ok,Pid}->
application_server:replace(Pid,Value);
{error,_}->
application_server:create(Value), %%创建子进程,并将value参数传入
application_store:insert(Key,Pid) %%存入ets表中
end.
lookup(Key)->
try %%先ets中看有没有
{ok,Pid} = application_store:select(Key), %%ets中都是key-pid对
{ok,Value} = application_server:fetch(Pid), %%handle_call会将#state{value}值返回
{ok,Value}
catch
_Class:_Exception -> %%三种:throw:Other ; exit:Reason; error:Reason
{error,not_found}
end.

delete(Key)-> %%只有lookup没有值应该error,其他多
case application_store:select(Key) of
{ok,pid}->
application_server:delete(Pid);
{error,_Reason}->
ok
catch

end.

OTP&ETS的更多相关文章

  1. 转载: Erlang Socket解析二进制数据包

    转自:http://www.itkee.com/developer/detail-318.html 今天在家里闲来无事,实践了一下Erlang的Socket的功能.记录一下在过程中遇到的一些问题,以及 ...

  2. [Erlang 0127] Term sharing in Erlang/OTP 上篇

    之前,在 [Erlang 0126] 我们读过的Erlang论文 提到过下面这篇论文: On Preserving Term Sharing in the Erlang Virtual Machine ...

  3. [Erlang 0119] Erlang OTP 源码阅读指引

      上周Erlang讨论群里面提到lists的++实现,争论大多基于猜测,其实打开代码看一下就都明了.贴出代码截图后有同学问这代码是哪里找的?   "代码去哪里找?",关于Erla ...

  4. Erlang ets -- something about cache continue

    上一次说到了实现一个简单cache 的基本思路和想法, http://www.cnblogs.com/--00/p/erlang_ets_something_about_cache.html 在文末, ...

  5. Erlang/OTP 中文手册

    http://erldoc.com/ Open Telecom Platform application array asn1rt base64 binary calendar code dbg di ...

  6. Erlang模块ets翻译

    概要: 内置的存储 描述: 这个模块是Erlang内置存储BIFs的接口.这些提供了在Erlang运行时系统中存储大量数据的能力,并且能够对数据进行持续的访问时间.(在ordered_set的情况下, ...

  7. 动态令牌-(OTP,HOTP,TOTP)-基本原理

    名词解释和基本介绍 OTP 是 One-Time Password的简写,表示一次性密码. HOTP 是HMAC-based One-Time Password的简写,表示基于HMAC算法加密的一次性 ...

  8. Erlang/OTP 17.0-rc1 新引入的"脏调度器"浅析

    最近在做一些和 NIF 有关的事情,看到 OTP 团队发布的 17 rc1 引入了一个新的特性“脏调度器”,为的是解决 NIF 运行时间过长耗死调度器的问题.本文首先简单介绍脏调度器机制的用法,然后简 ...

  9. 利用OTP为odoo增强安全访问

    两次验证是广泛应用于各大站点的验证机制,我们今天利用Google Authentication来实现Odoo的两次验证,防止撞库或密码泄露等引起的安全问题. 1. 二次验证的原理 参见 http:// ...

随机推荐

  1. flutter Dynamic updates 热更新 版本更新

    比较新的解释 https://juejin.im/entry/5c85c959f265da2d881b5eb8 https://my.oschina.net/u/1464083/blog/297880 ...

  2. 20175312 2018-2019-2 《Java程序设计》第7周学习总结

    20175312 2018-2019-2 <Java程序设计>第7周学习总结 教材学习内容总结 已依照蓝墨云班课的要求完成了第八章的学习,主要的学习渠道是PPT,和书的课后习题. 总结如下 ...

  3. 【.Net Core】Assets file project.assets.json not found. Run a NuGet package restore

    问题起因 添加 .net core的Project build失败. 提示以下error: Assets file project.assets.json not found. Run a NuGet ...

  4. Lintcode93-Balanced Binary Tree-Easy

    93. Balanced Binary Tree Given a binary tree, determine if it is height-balanced. For this problem, ...

  5. Redhat终端中文乱码解决

    文件中的中文以及命令反馈的中文能够正常显示,但是在终端中用ls等命令查看文件时会出现乱码. 我在i18n文件中加了下面两行内容(本来只有第一行),后来就能正常显示了.

  6. Python读写txt文件时的编码问题

    这个问题来自于一个小伙伴,他在处理中文数据时需要先把里面的文本过滤然后分词,因为里面有许多符号,不仅是中文标点符号,还有✳,emoji等奇怪的符号. 正常情况下,中文的str经过encode('utf ...

  7. xampp集成环境下重置mysql的密码

    第一步:打开两个命令行工具,都进入到你的xampp安装目录下的mysql下的bin目录,如我安装的位置是D:xampp/mysql/bin: 第二步:在完成第一步的情况下,输入:mysqld --sk ...

  8. bzoj 2286: [Sdoi2011]消耗战 虚树+树dp

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...

  9. HDU - 3652

    #include<stdio.h> #include<string.h> #include<math.h> #include<time.h> #incl ...

  10. windows,用c++调用mxnet做前向

    参考博客: https://blog.csdn.net/qq_34062105/article/details/82590553 https://blog.csdn.net/u012234115/ar ...