Programming Erlang读书笔记8: Concurrency Programming

在Erlang里:
1,创建和销毁进程非常快
2,进程间发送消息非常快
3,在所有的操作系统间进程行为一致
4,可以有大量的进程
5,进程不共享内存并且完全独立
6,与进程交互的唯一途径是发送消息

Concurrency Primitives
[code]
Pid = spawn(Fun)

Pid!Message

receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard2] ->
Expressions2;
...
after Time ->
Expressions
end
[/code]

Example
[code]
-module(area_server).
-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.
[/code]

Client-Server通信时需要通过self()传递client端PID
[code]
-module(area_server).
-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, Width, Ht}} ->
From ! {self(), Width * Ht},
loop();
{From, {circle, R}} ->
loop();
{From, Other} ->
From ! {self(), {error, Other}},
loop()
end.
%%%%%%%%%%%%%
1> Pid = area_server:start().
<0.36.0>
2> area_server:area(Pid, {rectangle, 10, 8}).
80
3> area_server:area(Pid, {circle, 4}).
50.2645
[/code]

自定义让当前进程sleep T毫秒的方法
[code]
sleep(T) ->
receive
after T ->
true
end.
[/code]

自定义Timer
[code]
-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.
[/code]

每个进程都有一个mailbox
发送消息到该进程时,消息被放入mailbox
当程序运行到receive语句时,启动一个timer
读取mailbox中的第一条消息,匹配Pattern1,2,...,如果消息匹配了,则从mailbox中删除掉,并执行该Pattern后的表达式
如果receive语句中没有匹配的Pattern,则将该消息从mailbox中删除并放入save queue,然后下一条消息进来匹配
如果mailbox中没有一条消息是匹配成功的,则进程suspend并等待下一次新的消息进来,下次有新消息时save queue里的消息不会再匹配
一旦有消息匹配,则已经放入save queue的消息按到达进程的顺序重新进入mailbox,如果设置了timer,则清空save queue
如果在等待消息时timer到点,则执行ExpressionsTimeout表达式并将保存的消息按到达进程的顺序放入mailbox

publishing一个process identifier,这样系统里所有process都可以和这个process交互,发布的process称为registered process
BIFs:
[code]
register(AnAtom, Pid)
unregister(AnAtom)
whereis(AnAtom) -> Pid | undefined
registered() -> [AnAtom::atom()]
[/code]

Example
[code]
1> Pid = spawn(fun area_server:loop/0).
<0.51.0>
2> register(area, Pid).
true
3> area ! {rectangle, 4, 5}.
Area of rectangle is 20
{rectangle,4,5}
[/code]

Example2
[code]
-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.

%%%%%%%%%%%%%%%%%%
1> clock:start(5000, fun() -> io:format("TICK ~p~n", [erlang:now()]) end).
2> clock:stop().
[/code]

Concurrent Program Template
[code]
-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.
[/code]

在loop里receive之后马上又调用loop,则loop称为tail-recursive方法
如果我们写一个方法F,F never returns,则需要确保在调用F之后不会调用其他方法,也不要将F用于List或Tuple的constructor,否则内存溢出

spawn with MFA:
[code]
spawn(Mod, FuncName, Args)
[/code]
使用Mod名、Func名和Args列表(成为一个MFA)来显式的调用spawn是确保系统动态加载代码(热修改)的正确方式
spawn with funs则不会动态加载代码

作业
[url=http://www.blogjava.net/raimundox/archive/2007/08/01/133863.html]Erlang Ring Benchmark[/url]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值