一、现实中的并发
在现实生活中,并发的模型有很多,比如当我们在路上开车,大脑会时刻定位着周围数十辆车甚至百辆,如果我们一次只关注一辆车,那么是很危险的,再比如,以人比作进程,世界比作系统,我们每个人都是独立的个体,我们都有自己的思想和要做的事情,如果我要和你产生联系,那么我就需要和你通讯,通过发送消息与接受消息我们可以共享我们所拥有的资源。
二、Erlang中的并发编程
Erlang的并发是基于进程的,他们是一些独立的小型虚拟机,可以执行Erlang函数。但此进程非彼进程,Erlang的进程是相对于Erlang语言而言的,而C++等语言的进程是基于操作系统而言。
1.基本的并发函数
-
Pid=spawn(Mod,Func,Args).
创建一个新的进程去运行Mod:Func(Args).前提是Func在Mod里已经export -
Pid=spawn(Fun).
使用这种spawn可以实现代码动态升级 -
Pid ! Message
向标识符为Pid的进程发送消息Message -
receive ... end
接受发送给某个进程的消息,语法如下:
receive
Pattern1 [when Guard1]->
Expressions1;
...
PatternN [when GuardN]->
ExpressionsN
end.
当接受到的消息不匹配Pattern1-N时,这条消息会被压入一个队列中,而进程会等待下一条消息
2.rpc函数(远程过程调用函数)
一个经典的rpc模型:
rpc(Pid,Request)->
Pid ! {self().Request},
receive
{Pid,Response} ->
Response
end.
3.带超时的接收after
receive
Pattern->
Expressions
after Time ->
Expressions2
end.
%当Time毫秒后,进程没有接受到匹配的消息,就会转到after下执行表达式序列
4.只有超时的接收(实现sleep())
sleep(T)->
receive
after T->
true
end.
5.超时为0的接收
flush_buffer() ->
receive
_Any ->
flush_buffer()
after 0 ->
true
end.
%如果没有超时字句就会陷入死循环,也可以用after 0来实现优先匹配
6.超时值为infinity(无穷大)的接收
永远不会触发超时,相当于没写
7.选择性接收
- a.当包含after时,进入receive语句就会启动一个计时器
- b.若receive的第一个消息匹配不上,就会丢尽队列中,直到消息都匹配过
- c.若队列里的消息都不匹配,进程就会被挂起,直到新消息进入才会继续运行
- d.一旦匹配成功,after就没用了
- e.计时器够钟之后,所有队列里的消息会重新回到邮箱
8.进程的全局注册
使用注册可以把进程的pid给公之于众,大家都可以通过一个原子去获取进程的pid,从而去进行通讯
-
register(atom,Pid)->bool()
arg1:原子类型
arg2:要注册在这个原子上的Pid
重复时注册失败 -
unregister(atom) -> bool()
移除注册信息,当进程结束或者崩溃了,会自动解除注册 -
whereis(atom) ->Pid | undefined
检测某个原子是否被注册,如果是就返回Pid,否则undefined -
registered()->[atom::atom()]
返回所有已注册进程的列表
9.尾递归问题
loop()->
receive
{From,Message}->
From ! {self(),Message},
loop(),
someFunc();
end.
上面的代码中,loop()后面还执行了一个someFunc() 但是系统永远不会执行他,却又认为loop()最终返回的肯定是最后一句someFunc(),所以会把someFunc()的地址作为返回结果,而递归一次就会保存一次这个返回地址,最终会导致内存崩溃,资源耗尽,所以我们应当使用尾递归,即递归函数放在最后一句,loop()与someFunc()对换。









网友评论