美文网首页
[Erlang开发之路]十一&十二、并发编程

[Erlang开发之路]十一&十二、并发编程

作者: 循环不计次 | 来源:发表于2019-07-19 14:51 被阅读0次

一、现实中的并发

在现实生活中,并发的模型有很多,比如当我们在路上开车,大脑会时刻定位着周围数十辆车甚至百辆,如果我们一次只关注一辆车,那么是很危险的,再比如,以人比作进程,世界比作系统,我们每个人都是独立的个体,我们都有自己的思想和要做的事情,如果我要和你产生联系,那么我就需要和你通讯,通过发送消息与接受消息我们可以共享我们所拥有的资源。

二、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()对换。

相关文章

网友评论

      本文标题:[Erlang开发之路]十一&十二、并发编程

      本文链接:https://www.haomeiwen.com/subject/gyxslctx.html