Erlang 是面向并发的函数式语言,Erlang的特性有:
并发性,分布式,健壮性,热代码升级等。
(其他特性如 递增式代码装载 软实时性 目前还不太理解).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Erlang 基础总结:
1.1. Erlang数据类型有
integer(整形);Atom(原子);
float(浮点数)在Erlang中无需关心浮点数大小;
reference(引用):引用是全局唯一的符号,用来比较两个引用是否相等;
引用可以通过erlang:make_ref()来创建;
pid(进程标识符-process identifier):pid由spawn()创建,
是Erlang进程的引用
1.2. Erlang 对于二进制的数据处理提供了非常强大的语法
常用的操作二进制数据的函数:
list_to_binary(List)->binary().
split_binary()
term_to_binary(Term)
binary_to_term()
1.3. Erlang最重要的数据类型就是列表和元组
Erlang List 常用元组操作:
tuple_size(Tupel) % 元组中元素个数
element(Th, Tuple) % 获取元组中第Th个元素
setelement(Th, Tuple, T) % 设置元组第Th个元素为 F
erlang:append_element(Tuple, T) %元组结尾添加一个元素T
记录:记录是元组的伪装,它提供了一个方法,把一个名称与元组中的一个元素对应起来;
记录使用方法:首先定义记录,并保存在一个.hrl文件中,Erlang程序引用该.hrl文件
就可以定义和操纵记录了。
1.4. Erlang List 列表常用操作:
map(Fun, List1) -> List2
foldl(Fun, Acc0, List) -> Acc1
merge(ListOfLists) -> List1
1.5. Erlang是没有字符串
String(字符串),Erlang是没有字符串的,
通过双引号引起来的字符系列。这种写法只不过是字符串里的ascii码组成的整数
列表,例如:字符串“cat”只是列表[97,99,116]的速记法。
1.6. 作为函数式的语言 Erlang变量不能第二次赋值,这样不用再去跟踪某个变量的一系
列些列的变化,可以通过模式匹配给变量赋值,以及从复合数据类型中提取值。
也可以控制函数的执行,比如
area({rectangle, Width, Ht}) ->Width * Ht;
area({circle, R}) ->3.14 * R * R .
程序会从前到后用函数头中的模式与调用参数匹配,如果匹配
成功,该子句对应的表达式就会被执行。
断言是一种用于强化模式匹配功能的
结构,使用断言可以在一个模式上做一些简单的变量测试和比较,
比如:max(X, Y) when X > Y ->X;
max(X, Y) ->Y.
1.7. 在Erlang中在Erlang中函数可以给变量赋值,可以作为其他函数做参数, 也可以作为其他函数的返回值。
1.8. Erlang没有循环,如果要实现循环只能通过递归来实现。
举个循环例子:
for(Max, Max, F) -> [F(Max)].
for(I,Max,F) ->[F(I)|for(I+1,Max, F)].
尾递归
如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的
因为模式匹配是自上而下的,所以递归的结束子句一定要写在前面,尾递归的实现需要借助辅
助变量,是对递归的"尾"调用的实现,结果都保存在形参中.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
关于Erlang的并发
Erlang是面向并发的,每一个Erlang中的并发活动成为一个进程。Erlang并发
设计原则:
世界是并发的;事物之间不共享数据;事务通过消息进行通信;事务会出现故障
2.1.进程启动
spawn(Module, Fun, [Argulent]).
进程的发送和接收原语 !(send) , receive
2.2.通过register可以给进程注册一个标识符,以便于和其他进程进行通信
Erlang 进程注册机制目前的限制是:
1:names只能是atom
2:一个进程只能注册一个name
3:不能进行高效的搜索和遍历,进程信息的检索是通过遍历检查进程的元数据完成的.
Gproc是Erlang进程注册机制的加强版,提供了如下原生进程注册没有的功能:
1:使用任意Erlang Term作为进程的别名
2:一个进程注册多个别名
****
gproc 可以给一个进程注册多个别名
属性是不唯一的,可以给多个进程注册同样的属性名称
gproc:reg()
gproc:send()
当gproc:send()第一个参数是已经注册的属性名称时就可以实现给多个进程发送消息、
实现群发。
2.3.并发进程的错误处理:
link(Pid) 当前进程和Pid进程建立链接,这样两个进程相互监视,当一方消亡时,系统
会给另一发发送退出信号,收到信号后,如果没有对接收特殊处理,默认接收进程一并
退出,可以用process_flag(trap_exit, true) 让进程成为系统进程,这样接收到传过来
的退出信号,就会做出一些处理而不退出。
2.3.1 如果自己创建的进程崩溃,自己也自行消亡,可以用
spawn_link()创建进程
如果自己创建的进程崩溃,自己需要做一些处理,
process_flag(trap_exit, true),
spawn_link().
2.3.2 进程之间的处理还可以用监控树.
2.4.节点间通信
只要分布式Erlang节点共享相同的cookie信息,他们之间就可以通信,
连接在一起的节点信息是共享的.
如果两个节点是存活的(Erlang:is_alive()=:=true), 却不能连接
(net_adm:ping/1=:=pang)
首先检查cookie是否相同,接下来查看DNS是否能够解析,或者
主机名和IP是否在/etc/hosts文件中配置
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
erlnag/OTP gen_server
Erlang的OTP behaviour是对一些通用编程模式的抽象,在用Erlang 语言做开发时可以在behavior基础
上快速构建出可用且可靠的功能。
gen_server:start_link(Name, Mod, InitArgs, Opts),
负责启动一切,它创建了一个名为Name的服务器程序,主要负责发送和接收消息
为了调用服务器程序,客户端调用gen_server:call(Name, Request)
这会导致调用handle_call/3函数,它主要用来处理同步请求,需要给
客户端发送返回结果。
gen_server:cast(Name, Request)
这会导致调用handle_cast/3函数,它主要用来处理异步请求,没有返回值。
handle_info/2这个方法的定位是处理同步请求,异步请求之外的消息,如果一个消息我们能明确的
知道是call还是cast就不要走这里;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
关于application
Erlang程序包含相互调用的函数,
函数组合在一起并在模块中定义,模块是Erlang代码的基本单元,一组功能模块,
可以打包成一个应用,作为一个单独的整体,一起启动,停止。
应用-->模块-->函数-->语句-->子语句-->表达式.......
application是Erlang代码和功能组织的形式之一.
application的设计目的是通过运行一个或者多个进程来完成一定功能.
为了能够管理这些进程的生命周期,需要通过supervisor进行管理.
4.1.Application至少包括的三个部分为:
(1)应用模块:主要包括如何启动和停止Application的函数start/2,stop/1;
(2)监控模块:监控树的代码实现;
(3)资源文件:.app文件,包含应用程序的信息。
4.2.监控树是由进程形成的一棵树,树顶端是监控进程,负责监控下方的进程,
下方的进程可以是工作进程也可以是其他监控进程。
如果监控树下方的进程崩溃了,监控进程负责按照 init/1 函数中的设置重新
启动下方的进程。
Erlang 四种监控策略:
1.one_for_one:
如果一个子进程停止,则只重启该子进程。
2.simple_one_for_one:
一个简化的one_for_one,所有的子进程都是同样的进程类型,并且是动
态添加的实例。
3.all_or_one:
如果任何一个子进程停止,所有其他子进程也停止,然后重启所有子进程
4.rest_for_one:
一个子进程停止,启动顺序在该子进程之后的其他子进程也停止,然后这
些停止的进程重启
4.3. 一个应用需要一个.app文件来描述,主要描述它包括哪些文件,参数等。
比较完整的资源文件如下:
{application,test, % 名称
[{description,"Test application"}, % 描述
{vsn, "1.0.0"}, % 版本
{id, Id}, % id 同 erl -id ID
{modules, [test_app,test_sup]}, % 所有模块,systools用来生成script/tar文件
{maxP, Num}, % 最大进程数
{maxT, Time}, % 运行时间 单位毫秒
{registered, [test_app]}, % 指定名称,systools用来解决名字冲突
{included_applictions, []}, % 指定子app,加载但不启动
{mod, {test_app,[]}}, % 启动模块,[]为参数
{env, []}, % 配置env,可以使用application:get_env获取
{applications,[kernel,stdlib]}]}. % 依赖项,启动app前,将会首先启动的app
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ets和dets是Erlang用于高效存储大量Erlang数据条目的两个
系统模块,他们提供大量的"键-值"搜索表,
1.ETS是内存存储,速度快
2.DETS是磁盘存储,可备份
3.创建表:ets:new
dets:open_file
4.插入:insert(table, X)
5.查找:lookup(table, Key)
6.释放:dets:close(tableid)
etd:delete(tableid)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Erlang 程序的编译 和 运行
rebar.config
deps 定义依赖文件rebar 常用命令
clean 去掉所有生成的文件
compile 编译源文件
delete-deps 删除rebar.config设置的依赖库源文件
get-deps 检索获取rebar.config 设置的依赖库源文件
当deps有更新的时候,可以用到这两个
generate 生成目标文件在命令行下运行程序:参数解释
-name 启动一个节点;
-config 指定配置文件;
-env 设置环境变量;关于环境变量:
如果环境变量在.app文件中设置,同时在-config指定的文件中设置,则
-config指定的文件中的会覆盖.app文件中的变量值,如果在命令行下
-env设置环境变量,在-config指定的文件中已经设置过,则命令行下设置的
会覆盖-config指定的文件中设置的变量值-pa 设置需要启动的编译过的模块的路径;
-s 执行特定函数,默认是start/0;
4.Erlang 常见的错误类型
badarg 参数错误,参数格式或类型错误
badarith 算术表达式错误,算术表达式中含有错误的参数
{badmatch,V} 模式匹配错误,V指具体的发生匹配错误的数值
function_clause 函数子句错误,没有找到匹配的函数子句
{case_clause,V} case匹配错误,没有找到匹配的case pattern
if_clause if子句错误,没有找到为ture的if子句
{try_clause,V} try匹配错误,执行try时,没有找到匹配的pattern
undef 函数未定义错误
{badfun,F} 函数错误
{badarity,F} 函数参数个数错误
timeout_value 超时参数错误,在receive.. after语法中,after对应的超时数据
错误(应为不小于0的integer或infinity
noproc Process 错误,Process不存在
{nocatch,V} throw未被catch
system_limit 系统限制错误,某些性能或数据达到系统极限
undef是遇见的做多的错误类型,
如果调用一个eralng函数时发生undef错误,可能是以下几种原因:
(1)系统中不存在这个模块或函数,可能是拼写错误。
(2)系统中有这个模块,但没有编译。
(3)已经编译了,但它所在的目录不在erlang的加载路径中。
(4)加载了几个不同版本,我们可以通过code:clash()函数来看一下是否有重名的模块。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
关于版本控制:
(1)
git 一个分布式的版本控制系统
常用的git 命令有
(1)首先获取要编辑文件的最新版本
git pull
(2)然后开始编辑文件
(3)提交编辑好的文件
git add 文件名
git commit -m “备注”
(4)把提交过的文件推送到远程
git push origin master
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
在命令行下运行程序:
文件理解:
-name 启动一个节点;
-config 指定配置文件;
-env 设置环境变量;
-pa 设置需要启动的编译过的模块的路径;
-s 执行特定函数,默认是start/0;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- rebar.config
deps 定义依赖文件
rebar 常用命令
clean 去掉所有生成的文件
compile 编译源文件
delete-deps 删除rebar.config设置的依赖库源文件
get-deps 检索获取rebar.config 设置的依赖库源文件
当deps有更新的时候,可以用到这两个
generate 生成目标文件
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
关于环境变量:
在命令行下-env 设置的环境变量如果在。config文件中设置过,
badarg 参数错误,参数格式或类型错误
badarith 算术表达式错误,算术表达式中含有错误的参数
{badmatch,V} 模式匹配错误,V指具体的发生匹配错误的数值
function_clause 函数子句错误,没有找到匹配的函数子句
{case_clause,V} case匹配错误,没有找到匹配的case pattern
if_clause if子句错误,没有找到为ture的if子句
{try_clause,V} try匹配错误,执行try时,没有找到匹配的pattern
undef 函数未定义错误
{badfun,F} 函数错误
{badarity,F} 函数参数个数错误
timeout_value 超时参数错误,在receive.. after语法中,after对应的超时数据错误(应为不小于0的integer或infinity
noproc Process 错误,Process不存在
{nocatch,V} throw未被catch
system_limit 系统限制错误,某些性能或数据达到系统极限
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
screen的应用、
screen -x
screen -ls
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ets
Erlang语法:数据库
--------------------------------------
1.ETS是内存存储,速度快
2.DETS是磁盘存储,可备份
3.创建表:ets:new
dets:open_file
4.插入:insert(table, X)
5.查找:lookup(table, Key)
6.释放:dets:close(tableid) etd:delete(tableid)
7.Mnesia数据库:
创建表:-record...
选取所有数据:do(qlc())...
选取部分列:
按条件选取:
关连查询:
增加数据:mnesia:write()
删除数据:mnesia:delete()
事务管理:mnesia:transaction(F)
取消事务:mnesia:abort()
启动表查看器:tv:start().
字符串列表转为字符串的方法:
L1 = ["a","b","c","d"],
binary_to_list(list_to_binary(L1)).
"abcd"