`
solingye
  • 浏览: 20056 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Erlang并发

阅读更多
erlang进程之间没有共享内存,每一个进程都有它自己的内存,想要修改其他进程的内存,你只能向它发送一条消息。

erlang的进程不共享内存,没有锁的概念。

erlang的错误侦测机制:进程之间可以相互链接。如果一个进程消亡,那么跟这个进程有链接的进程会得到一条消息,被告诉进程已经消亡,及其原因。

erlang进程的三个原语:spawn,send,receive.

Pid = spawn(Fun):创建一个新的并发进程。对于Fun求值,返回一个Pid,可以使用Pid向进程发送消息。

Pid!Message:想标识符为Pid的进程发送消息,消息发送是异步的。!是发送消息符。它的返回值是它发送消息的本身。

receive...end:接收一个发送给当前进程的消息。
语法:
receive 
	Pattern1 [when Guard] ->
		Expre1;
        Pattern1 [when Guard] ->
		Expre1;
	…
end.

例子:
-module(process).
-export([loop/0]).
loop() ->
    receive
        {rectangle,Width,Ht} ->
            io:format("Area of rectangle is ~p~n",[Width*Ht]),
            loop();
        {circle,R} ->
            io:format("Area of circle is ~p~n",[3.14*R*R]),
            loop();
        Other ->
            io:format("I don't know what the area of a ~p is ~n",[Other]),
            loop()
     end.

在shell中创建一个进程:
Pid = spawn(fun process:loop/0). 
//Pid = spawn(fun() -> loop() end).
//Pid = spawn(process,loop,[]).
Pid ! {rectangle,5,4}. //发送消息


客户/服务器架构是erlang的核心部分。erlang的消息传递被用于客户机和服务器之间的通讯。
客户端总是通过向服务器发送请求来发起一个计算,服务器则在计算出结果之后向客户端发送一个响应。
客户机必须在请求中包含一个服务器可以响应的地址。客户自己的Pid可以用self()表示。
Pid ! {self(),{rectangle,4,5}}.


接收代码改为:
loop() ->
    receive
        {From,{rectangle,Width,Ht}} ->
            Result = Width*Ht,
            From ! Result,
            loop();
        {From,{circle,R}} ->
            Result = 3.14*R*R,
            From ! Result,
            loop();
        {From,Other} ->
            From ! Other,
            loop()
     end.


完整代码:
-module(process).
-export([start/0,area/2]).
start() ->
    spawn(fun loop/0).

area(Pid,What) ->
    send(Pid,What).

send(Pid,Request) ->
    Pid ! {self(),Request},
    receive
        {Pid,Response} ->
            Response
        end.

loop() ->
    receive
        {From,{rectangle,Width,Ht}} ->
            Result = Width*Ht,
            From ! {self(),Result},
            loop();
        {From,{circle,R}} ->
            Result = 3.14*R*R,
            From ! {self(),Result},
            loop();
        {From,Other} ->
            From!{self(),{error,Other}},
            loop()
     end.


查看系统所允许的最大进程数:erlang:system_info(process_limit).
如果要超过系统允许的最大进程数,必须在启动erlang的时候带上+P参数,例如:
erl +P 500000.


带超时的receive:有时候,如果某个消息迟迟不来,receive语句可能进入无限的等待之中,为了避免这种情况,在receive语句里面加上一个超时,这个超时设定了进程接收消息时最长的等待时间。语法:
receive 
	Pattern1 [when Guard] ->
		Expre1;
        Pattern1 [when Guard] ->
		Expre1;
	…
after Time ->
	Expres
end.

如果在进入receive表达式后在Time所规定的毫秒数内没有收到能够匹配的消息,那么receive就会停止等待,并对Expres求值。

只有超时的receive:可以写一个只有超时的receive语句,用它来让当前进程暂停Time毫秒。
sleep(T) ->
	receive
	after T->
		true
	end.


无限等待超时进行接收:如果receive语句的超时值被设定为原子infinity,那么系统就永远都不会触发超时。

实现一个计时器:
-module(time).
-export([start/2,cancel/1]).
start(Time,Fun) ->
    spawn(fun() -> time(Time,Fun) end).

cancel(Pid) ->
    Pid ! cancel.

time(Time,Fun) ->
    receive cancel ->
        void
    after Time ->
        Fun()
end.


send其实并非把一个消息传递到一个进程中去,而是把一个消息发送到进程的邮箱中去,同理,receive则试图把一条消息从那个进程邮箱中删除。
erlang中每个进程都有与之对应的邮箱,当向进程发送消息的时候,消息被送入到邮箱之中。当系统对receive语句进行求值的时候,就是对进程邮箱进行检查的唯一机会。
receive内部的工作机制:
1.当进入一个receive语句时,我们启动一个计时器(只有在表达式中存在after段时才会计时)。
2.从邮箱中读取一条消息,然后尝试对Pattern1,Pattern2等进行模式匹配,如果匹配成功,消息则从邮箱中删除,对应的模式之后的表达式就会被求值。
3.如果邮箱中的第一个消息不能匹配receive语句中的任何一个模式,那么会将第一个消息从邮箱中删除并送入一个“保存队列”。然后继续尝试从邮箱中取第二条消息,这个过程不断重复,知道找到匹配的模式,或者邮箱中的所有消息全部检查完毕。
4.如果邮箱中的所有消息都不匹配,那么就挂起进程,直到下一次又有新消息进入邮箱时在对该进程重新调度执行。当一个新消息到达时,只会对新消息进行匹配,不会对“保存队列”中的消息进行再次匹配。
5.一个消息如果匹配,那么存入“保存队列”中的所有消息就会按照他们到达进程的时间先后顺序重新放回邮箱中。这时,如果启动了一个计时器,那么这个计时器会被清空。
6.我们在等待消息的时候触发了计时器,那么对表达式ExpreTimeOut求值然后把存入“保存队列”的所有消息按照他们到达进程的时间先后顺序重新放回邮箱。

注册进程:
如果想向一个进程发送消息,就必须知道它的Pid,erlang提供了一种机制可以用于发布一个进程的标识符以便其他进程可以与之通信。这种进程叫做注册进程。
register(AnAtom,Pid):将一个进程Pid注册为一个名为AnAtom的原子。
unregister(AnAtom):移除AnAtom相应的进程的所有注册信息。如果一个进程死亡,那么它会自动被取消注册。
whereis(AnAtom) -> Pid|undefined:判断AnAtom是否已经被其他进程注册。
registered() -> [AnAtom::atom()]:返回一个系统中所有已经注册的进程名称列表。

时钟程序:
-module(clock).
-export([start/2,stop/0]).
start(Time,Fun) ->
    register(clock,spawn(fun() -> tick(Time,Fun) end)).

stop() ->
    clock ! stop.

tick(Time,Fun) ->
    receive stop ->
        void
    after Time ->
        Fun(),
        tick(Time,Fun)
    end.


并发程序template:
-module(template).
-compile(export_all).

start() ->
    spawn(fun() -> loop([]) end).

rpc(Pid,Request) ->
    Pid ! {self(),Request},
    receive
        {Pid,Response} ->
            Response
    end.
loop(X) ->
    receive Any ->
        io:format("~p~n",[Any]),
        loop(X)
    end.


尾递归技术:编译尾递归函数可以使在一系列语句最后的一个函数调用可以被替换为一个简单的跳转指令。指向被调用函数的开头。这就意味着一个尾递归函数可以无限循环而不需要消耗栈空间。

spawn(Mod,FunName,Args):创建一个新进程,Args是一个形如[arg1,arg2…]的参数列表,新进程会从函数Mod:FuncName(arg1,arg2…)开始执行。这样的方式创建进程,代码可以很好的进行动态更新。

一个进程如果使用exit(normal)退出或者运行完所有的代码然后退出被称为正常退出。

一个进程如果发生了运行时错误(例如除以0,试图调用一个不存在的函数),将因错误而结束,被称为异常退出,一个进程执行exit(Reason),Reason为一个除了atom normal之外的term,也被看做是异常退出。

一个进程可以设置到其他进程的链接(link),进程之间通过link(Other_Pid)来建立自身和Other_Pid进程的双向链接。当一个进程终止的时候,将给每一个与他建立了链接的进程发送一个信号,这个信号包括发送者的Pid和进程结束的原因。

缺省情况下,一个进程将忽略接收到的正常退出信号。
对于异常退出,缺省处理将忽略所有传递给接收进程的消息并且杀死该进程。
spawn_link在完成spawn函数功能的同时建立了一个与新创建的进程的链接。
我们可以修改一个进程接收到异常退出信号时的缺省退出行为,所有的信号都被转换为一个格式为{'EXIT',FromPid,Reason}的普通消息并且被添加到消息队列中。我们可以通过process_flag(trap_exit,true)来实现该功能。




分享到:
评论

相关推荐

    erlang并发编程 .pdf

    在《Erlang并发编程》一书中,详细介绍了Erlang语言的核心并发模型和编程范式,包括但不限于串行编程、进程创建、进程间通信、分布式编程以及错误处理等。书中指出Erlang的并发性能得益于其轻量级进程,这些进程是由...

    erlang并发编程中文翻译(cpie-cn).zip

    《Erlang并发编程》是一本深入探讨Erlang编程语言并发特性的书籍,中文翻译版为《erlang并发编程中文翻译(cpie-cn...书中涵盖了Erlang并发编程的基础概念、高级技巧以及实际案例,是深入理解Erlang并发特性的宝贵资源。

    erlang并发编程实战源代码

    erlang并发编程实战源代码erlang并发编程实战源代码

    erlang并发编程

    Erlang并发编程是Erlang语言的核心特性之一,它为构建高效、容错的分布式系统提供了强大的工具。Erlang是一种函数式编程语言,特别适合处理并发和实时系统,因其在电信行业的广泛应用而闻名。以下是一些关于Erlang...

    Erlang并发编程 part1

    erlang并发编程,erlang之父Joe Armstrong得原著之一。

    erlang 深度分析

    Erlang并发性能调测 - **Percept模块**: R12B版本中引入的新工具。 - **功能**: 提供了更精确的并发性能测试能力。 - **应用场景**: 对Erlang程序进行性能优化。 #### 31. Erlang热更新 - **概念**: 在不重启服务...

    Erlang OTP并发编程实战 附书源码

    Erlang OTP并发编程实战是深入理解Erlang并发特性和 OTP(Open Telephony Platform)设计原则的关键资源。这本书的附书源码包含了14个章节的实例代码,旨在帮助读者通过实践掌握Erlang在分布式系统、容错以及高并发...

    erlang资源

    这个“erlang资源”包含两本PDF书籍——《Erlang并发编程》和《Erlang入门手册》,它们是深入理解和学习Erlang语言的关键资料。 《Erlang并发编程》这本书可能涵盖了以下知识点: 1. **并发模型**:Erlang的并发...

    erlang9.rar

    OTP库提供了许多实用的模块,如gen_server、gen_event和gen_fsm,这些都是Erlang并发编程的基础。 总而言之,Erlang9.rar是一个包含Erlang/OTP 20.0 Windows 64位安装程序的压缩包,主要用于安装Erlang环境,以...

    erlang官方资源包

    总结起来,"otp_src_21.3.tar.gz"是一个包含Erlang OTP框架源代码的压缩包,对于理解Erlang并发模型、开发基于OTP的系统以及搭建RabbitMQ服务器至关重要。通过学习和使用这些资源,开发者可以构建出高效、健壮的...

    erlang 程序设计 源码

    进程间通信通过消息传递实现,这是Erlang并发模型的核心。 2. **故障恢复与容错**:Erlang支持热代码替换,可以在运行时更新代码而不会中断服务。此外,进程之间独立运行,一个进程的崩溃不会影响其他进程,这使得...

    多核时代 Erlang的时代

    erlang 并发 编程 开发 语言

    ERLANGOTP并发编程实战清晰中文版

    erlang otp学习文档 学习还不错的

    Erlang深度分析

    理解Erlang进程的创建、销毁和消息传递机制是掌握Erlang并发编程的关键。 ##### 4.2 网络编程 Erlang在构建网络应用方面表现出色,提供了丰富的网络编程接口,如gen_tcp、gen_udp等。同时,Erlang还支持多种网络...

    一个我自己学习Erlang的聊天室服务器及客户端代码

    【Erlang聊天室服务器及客户端代码解析】 在IT领域,Erlang是一种面向并发、分布式、容错的编程语言,特别适合构建...通过学习这个案例,开发者可以加深对Erlang并发编程和Java网络编程的理解,以及跨语言通信的实践。

    远古封神+英雄远征的ERLANG游戏服务器代码

    总结起来,这个压缩包包含的《远古封神》和《英雄远征》的Erlang游戏服务器源码,为开发者提供了实践ERLANG并发特性和优化游戏服务器的实例。通过深入分析这些源码,我们可以学习到游戏服务器的设计原则,提高在实际...

    ErlangOTP 21.3.zip

    OTP是Erlang生态系统的重要组成部分,提供了许多预先设计好的行为模式(如 gen_server、gen_event 和 supervisor),这些模式使得开发者能够快速构建出符合Erlang并发哲学的应用程序。 otp_src_21.3.tar是Erlang ...

    Erlang OTP并发编程实战(中文版)

    **Erlang OTP并发编程实战** 是一本专为开发者深入理解Erlang OTP并发机制而设计的实战指南。OTP(Open Telecom Platform)是Erlang编程语言的核心组件,提供了强大的并发处理能力和分布式系统构建框架。这本书以...

    Concurrent Programming in ERLANG (P1-90)

    客户端-服务器模型是Erlang并发编程中常见的一种架构模式。服务器进程负责接收来自客户端进程的请求,并根据请求提供相应的服务。 **5.6 进程调度、实时性和优先级** 进程调度决定了进程何时以及如何被选择来执行...

    适用于windows版本的 Erlang24 and RabbitMQ server 3.8.16下载

    1. **Erlang并发模型**:Erlang采用轻量级进程(processes)实现并发,这些进程之间通过消息传递进行通信,提供高并发性和低延迟。 2. **OTP框架**:OTP(Open Telecom Platform)是一组设计原则和库,为Erlang应用...

Global site tag (gtag.js) - Google Analytics