《Erlang程序设计》学习笔记-第2章 并发编程

http://blog.csdn.net/karl_max/article/details/3977860

1. 并发原语:

(1) Pid = spawn(Fun) %% 创建一个新的并发进程,用于对Fun求值。

(2) Pid ! Message %% !是发送操作符,消息发送是异步的,返回结果是消息本身,所以Pid1!Pid2!...!M可以向多个进程发送消息M。

(3) receive ... end %% 接收一个发送给当前进程的消息,是同步的。语法:

receive

Pattern1 [when Guard1] -> Expressions1;

Pattern2 [when Guard1] -> Expressions2;

...

end

如果没有匹配任何模式也不会抛出异常,消息会留给后续过程来处理,然后等待下一个消息。

2. area_server_final.erl:一个计算面积的程序的客户机和服务器, 其中用start()封装了发启一个服务器进程,用area封装了发起一个远程调用(rpc),用loop实现的服务器循环,以及在发送和接收消息时判断进程ID等,这些方法都很有用。

-module(area_server_final).

-export([start/0, area/2]).

start() -> spawn(fun loop/0).

area(Pid, What) ->

rpc(Pid, What).

rpc(Pid, Request) ->

Pid ! {self(), Request},

receive

{Pid, Response} -> Response;

end.

loop() ->

receive

{From, {rectangle, W, H}} ->

From ! {self(), W*H},

loop();

{From, {circle, R}} ->

From ! {self(), 3.14159*R*R};

loop();

{From, Other} ->

From ! {self(), {error, Other}},

loop()

end.

在erlang shell中测试之

1> Pid = area_server_final:start().

2> area_server_final:area(Pid, {rectangle, 10, 8}).

3> area_server_final:area(Pid, {circle, 4}).

3. erlang:system_info(process_limit).可以获取虚拟机允许的进程上限(一般为32767),可以通过在启动erl时+P N来修改这个值,如:erl +P 500000

4. @spec statistics(runtime) -> {总CPU运行时间, 从上次调用以来的CPU运行时间}

@spec statistics(wall_clock) -> {总的真实消耗时间,从上调用以来的真实消耗时间}

真实时间包括运行过程中读写硬盘等的时间。

注意:返回的时间*1000后是微秒

5. receive的等待超时语法:

receive

Pattern1 [when Guard1] -> Expressions1;

Pattern2 [when Guard1] -> Expressions2;

...

after Time -> %% Time是毫秒

Expressions

end

6. 自定义的sleep,只有超时的receive

sleep(T) ->

receive

after T ->

true

end.

7. 超时为0的receive的妙用(还能想出别的用法吗?)

(1)清空进程邮箱里的所有消息:

flush_buffer() ->

receive

_Any -> flush_buffer()

after 0 ->

true

end.

(2)优先接收alarm消息,如果邮箱里有大量的消息,这一方法效率很低(有其它方法吗?)

priority_receive() ->

receive

{alarm, X} ->

{alarm, X}

after 0 ->

receive

Any -> Any

end

end.

8. 如果超时值是原子infinity,则永远不会超时。(这样有什么用呢?不太明白书上所说的情况。)

9. 用receive超时实现一个计时器:

-module(stimer).

-export([start/2, cancel/1]).

start(Time, Fun) -> spawn(fun() -> timer(Time, Fun) end).

cancel(Pid) -> Pid ! cancel.

timer(Time, Fun) ->

receive

cancel -> void

after Time -> Fun()

end.

10. receive的工作机制(选择性接收)

(1)启动一个计时器(在有after的情况下)。

(2)从进程邮箱中取出第一个消息,进行模式匹配,如果匹配成功,则从邮箱中删除之。

(3)如果没有匹配成功,则把取出的消息放入“保存队列”,然后继续取消息。重复这一步,直到匹配成功,或邮箱为空。

(4)如果没有匹配成功且此时邮箱为空,则挂起进程,等待新消息进入。注意,当有新消息进入时,只对新消息匹配。

(5)如果有一个消息匹配成功,则把保存队列中的消息按时间顺序放入到进程邮箱中。这时,将计时器清空。

(6)如果在等待消息时,计时器触发,则退出等待,进入after表达式,并将保存队列按时间顺序放回到进程邮箱中。

11. 注册进程:

register(AnAtom, Pid). %% 如果这个原子已经被注册了,这个调用会失败

unregister(AnAtom). %% 如果一个进程已经死亡,它会被自动取消注册

whereis(AnAtom) -> Pid | undefined

registered() -> [AnAtom:atom()] %% 返回系统中所有注册进程的列表。

进程注册的原子可以像进程Pid一样使用。

12. 并发程序模板:

-module(ctemplate).

-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("Received:~p~n", [Any]),

loop(X)

end.

13. 尾递归技术:

尾递归在编译时可以优化为一个跳转指令,所以可以无限循环下去。尾递归要确保函数F在调用自身之后,不再调用任何东西,也不要在列表或元组的构造器中使用F。

14. 想要代码在运行时能够动态更新,要用下面的spawn:

spawn(Mod, FuncName, Args).

其中Args是形如[A1, A2, ..., AN]的参数列表。

显式指明模块,函数和参数列表的形式被称为MFA。

时间: 2025-01-02 19:05:18

《Erlang程序设计》学习笔记-第2章 并发编程的相关文章

Python学习笔记__16.2章 TCP编程

# 这是学习廖雪峰老师python教程的学习笔记 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示"打开了一个网络链接",而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可. 1.客户端 大多数连接都是可靠的TCP连接.创建TCP连接时,主动发起连接的叫客户端,被动响应连接的叫服务器. 1.1.创建一个基于TCP连接的Socket,获取新浪首页 # 导入socket库: import socket # 创建一个socket,AF_INET

Java学习笔记—第十三章 数据库编程入门

第十三章 数据库编程入门 了解JDBC Java中对数据库的访问主要是通过JDBC进行的.JDBC是Java数据库连接技术(Java Database Connectivity)的简称,是用于执行SQL语句的API,可以为多种关系数据库提供统一访问.由一组用Java语言编写的类和接口组成.(SQL是Structure Query Language的缩写,意义为结构化查询语言,是一种标准的关系数据库访问语言.) JDBC的工作机制 使用JDBC完成对数据库的访问主要包括以下五个层次:Java应用程

《erlang程序设计》学习笔记-第3章 分布式编程

http://blog.csdn.net/karl_max/article/details/3985382 1. erlang分布式编程的基本模型 (1) 分布式erlang:这种模型可以让我们在一个紧密耦合的计算机集群上编写程序. (2) 分布式erlang应用程序运行在一个可个这个进程的环境中.一个局域网的不同集群之间,但在同一个防火墙里面. (3) 基于套接字的分布式应用:使用TCP/IP套接字,我们可以编写运行在非信任环境中的分布式应用程序.2. 编写分布式程序的步骤: (1)先在一个非

javascript高级程序设计 学习笔记 第五章 上

第五章 引用类型的值(对象)是引用类型的一个实例.在 ECMAScript 中,引用类型是一种数据结构, 用于将数据和功能组织在一起.它也常被称为类,但这种称呼并不妥当.尽管 ECMAScript 从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构.引用类型有时候也被称为对象定义,因为它们描述的是一类对象所具有的属性和方法. 对象是某个特定引用类型的实例.新对象是使用 new 操作符后跟一个构造函数来创建的. 构造函数本身就是一个函数,只不过该函数是出于创建新

JavaScript高级程序设计学习笔记第六章--面向对象程序设计

1.ECMAScript没有类的概念,ECMA-262 把对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”,有点类似于散列表 2.ECMAScript 中有两种属性:数据属性和访问器属性. 数据属性: [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性. [[Enumerable]]:表示能否通过 for-in 循环返回属性. [[Writable]]:表示能否修改属性的值. [[Valu

JavaScript高级程序设计学习笔记第五章--引用类型(函数部分)

四.Function类型: 1.函数定义的方法: 函数声明:function sum (num1, num2) {return num1 + num2;} 函数表达式:var sum = function(num1, num2){return num1 + num2;};//注意有个分号 构造函数的方式:var sum = new Function("num1", "num2", "return num1 + num2");// 2.函数的重复声

JavaScript高级程序设计学习笔记第三章--基本概念

一.标识符: 1.区分大小写 2.命名规则: 第一个字符必须是一个字母.下划线(_)或一个美元符号($) 其他字符可以是字母.下划线.美元符号或数字 标识符中的字母也可以包含扩展的 ASCII 或 Unicode 字母字符(如 À 和 Æ) ,但不推荐这样做. 不能把关键字.保留字.true.false和null用作标识符 3.书写方式:最好按照驼峰大小写格式书写,就是第一个字母小写,剩下的每个单词的首字母大写,但不强制这么做二.注释(两种方式) 单行注释:// 多行注释:/*……*/ 三.严格

JavaScript高级程序设计学习笔记第四章--变量、作用域和内存问题

1.变量可能包含两种不同数据类型的值:基本类型值和引用类型值. 基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象. 2.变量复制 如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上,两个变量可以参与任何操作而不会相互影响. 当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中.不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象.复制操作结束

<<Python基础教程>>学习笔记 | 第14章 | 网络编程

Python是个很强大的网络编程工具,原因有二: 1. Python内有很多针对常见网络协议的库 2. Python在处理字节流方面的优势 本章主要内容: 探讨Python标准库中的一些网络模块,探讨SocketServer类,最后是Twisted框架. ------ 相关模块 Socket模块 基本组件,用于两个程序之间的信息通道.套接字包括两个: 服务器套接字和客户端套接字.创建一个服务器套接字后,让它等待连接,这样它就在某个网络地址处监听.客户端套接字负责:简单的连接,完成事务,断开连接.