《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。
《Erlang程序设计》学习笔记-第2章 并发编程的更多相关文章
- 《erlang程序设计》学习笔记-第3章 分布式编程
http://blog.csdn.net/karl_max/article/details/3985382 1. erlang分布式编程的基本模型 (1) 分布式erlang:这种模型可以让我们在一个 ...
- JavaScript高级程序设计学习笔记第三章--基本概念
一.标识符: 1.区分大小写 2.命名规则: 第一个字符必须是一个字母.下划线(_)或一个美元符号($) 其他字符可以是字母.下划线.美元符号或数字 标识符中的字母也可以包含扩展的 ASCII 或 U ...
- JavaScript高级程序设计学习笔记第十三章--事件
事件冒泡: IE 的事件流,事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档).例如: <!DOCTYPE html> <htm ...
- JavaScript高级程序设计学习笔记第十一章--DOM扩展
1.对 DOM 的两个主要的扩展是 Selectors API(选择符 API)和 HTML5 2.Selectors API Level 1 的核心是两个方法: querySelector()和 q ...
- JavaScript高级程序设计学习笔记第六章--面向对象程序设计
1.ECMAScript没有类的概念,ECMA-262 把对象定义为:“无序属性的集合,其属性可以包含基本值.对象或者函数.”,有点类似于散列表 2.ECMAScript 中有两种属性:数据属性和访问 ...
- JavaScript高级程序设计学习笔记第五章--引用类型(函数部分)
四.Function类型: 1.函数定义的方法: 函数声明:function sum (num1, num2) {return num1 + num2;} 函数表达式:var sum = functi ...
- JavaScript高级程序设计学习笔记第五章--引用类型
一.object类型 1.创建object类型的两种方式: 第一种,使用构造函数 var person = new Object();或者是var person={};/与new Object()等价 ...
- JavaScript高级程序设计学习笔记第四章--变量、作用域和内存问题
1.变量可能包含两种不同数据类型的值:基本类型值和引用类型值. 基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象. 2.变量复制 如果从一个变量向另一个变量复制基本类型的值,会在 ...
- Go语言学习笔记(4)——并发编程
Golang在语言级别支持了协程,由runtime进行管理. 在Golang中并发执行某个函数非常简单: func Add(x, y int) { fmt.Println(x + y) } func ...
随机推荐
- Incapsula免费日本CDN加速和CDNZZ香港CDN节点加速
Incapsula免费日本CDN加速和CDNZZ香港CDN节点加速 免费的CDN对于那些将空间放在美国的博客网站加速效果是最好的,CDN可以解决国内连接美国的网络线路经常抽风和访问速度时好时坏的问题, ...
- stackFromBottom-listview 内容从底部开始填充
今天遇到了一个问题,就是listview虽然占满了整个屏幕,但是,当它的内容只有几条的时候,它会从底部开始显示,上面留有空白.后来进入xml发现,listview有个属性stackFromBottom ...
- 报错 关于python的x和y不等长
ValueError: shape mismatch: objects cannot be broadcast to a single shape 这个错误可能是因为传入的两个参数数据长度不一样,比如 ...
- document.write的注意点
如果给button点击事件添加document.write会消除页面所有元素,包括button按钮 <!DOCTYPE html> <html> <head> &l ...
- 【CS Round #43 D】Bad Triplet
[链接]点击打开链接 [题意] 给你n个点m条边的无权无向联通图; 让你找3个点A,B,C 使得A->B=B->C=A->C 这里X->Y表示点X到点Y的最短路长度. [题解] ...
- python3怎样画二维点图
引用自:http://www.cnblogs.com/super-zhang-828/p/4792206.html import matplotlib.pyplot as pltplt.plot([1 ...
- Maven使用yuicompressor-maven-plugin打包压缩css、js文件
最近项目想使用在maven打包的时间压缩js,css文件,采用yuicompressor-maven-plugin插件进行压缩,但只是压缩减小大小,提高请求速度,并没有对js进行混淆.下面就写一下这个 ...
- jmeter与apache测试网站并发
本文主要介绍性能测试中的常用工具jmeter的使用方式,以方便开发人员在自测过程中就能自己动手对系统进行自动压测和模拟用户操作访问请求.最后还用linux下的压测工具ab做了简单对比. 1. ...
- 9.8 Binder系统_c++实现_内部机制1
1. 内部机制_回顾binder框架关键点 binder进程通讯过程情景举例: test_server通过addservice向service_manager注册服务 test_client通过get ...
- 9.2 Binder系统_驱动情景分析_服务注册过程
1. 几个重要结构体的引入给test_server添加一个goodbye服务, 由此引入以下概念: 进程间通信其实质也是需要三要素:源.目的.数据,源是自己,目的用handle表示:通讯的过程是源向实 ...