Erlang实战练习(四)

通过前几次的练习实践相信大家对Erlang编程有了基本的认识和了解,本文通过二分搜索、echo server、进程环三个实战练习认识Erlang中进程的通信的基础,通过本次实战,主要是感受Erlang创建进程、发送消息、接受消息的过程,我们知道,Erlang并不是共享内存的通信,Erlang中节点与节点、进程与进程之间的通信都需要进行消息传递,这个我已经在前几次讨论过了。

好了,废话少说,言归正传吧。

练习1:二分搜索:从一个已排好序的列表中寻找是否包含某元素,返回true/false。

这个跟前面几次练习一样,温故列表操作,代码如下:

-module(bisearch).
-export([bi_search/2,getMiddle/1,value/2,len/1]).

len([]) -> 0;
len([H|T]) -> 1 + len(T).

head([]) -> null;
head([H|T]) -> H.

value(0,L) -> 
    if 
        L =:= [] -> 
            %%io:format("hedad=false~n"),
            false;
        L =/= []->
            %%io:format("head=~p~n",[head(L)]),
            head(L)
    end;
value(N,[H|T]) -> value(N-1,T).

getMiddle([H]) -> H;
getMiddle(L) ->  
    Loc = len(L) div 2,
    value(Loc,L).
 
%% 函数bi_search/2:给定一个列表,查找X所在的位置。 bi_search(L,X)
-> Middle = getMiddle(L), if Middle =:= false -> false; Middle =:= X -> true; Middle < X -> Left = [E||E <- L,E > Middle], bi_search(Left,X); Middle > X -> Right = [E||E <- L,E < Middle], bi_search(Right,X) end.

由于代码是很久以前写的,很多地方都是自己编的,没有使用系统模块中的函数功能,因此,看起来可能比较繁琐,例如求列表长度、求列表表头等系统都有自定义的函数。get_middle/1主要是求出列表的中间元素。

练习2:

代码如下:

-module(echo).
-export([start/0,loop/1,print/1,stop/0]).

start() ->
    register(eserver,spawn_link(fun() -> loop([])end)).
    
loop(X) ->
    receive
        stop ->
                 io:format("Server has stopped!~nSee you!~n"),
                 void;
        Term ->
            io:format("Server Received:~p~n",[Term]),
            loop(X)
    end.
            
print(Term) -> 
    eserver ! Term. %%向进程发送Term消息,发送原语不是send,而是感叹号!

stop()
-> eserver ! stop.

spawn_link是Erlang系统的一个内建BIF(Built In Function),它是用于创建一个进程,并将当前进程与创建进程链接起来。

register也是Erlang系统的一个BIF,它是只将一个原子与一个Pid关联起来,本代码中原子eserver与新创建的进程关联起来。

程序编译运行如下:

 

练习3:进程环:创建N个进程,这N个进程组成一个进程环,然后将Message沿着环传送M次。

问题中提示,可以采用两种方法:一为集中式控制,二为分布式控制,我采用的集中式控制,先使用createProcess/2创建N-1个进程(当前进程为控制进程,也进行消息传递工作),然后从第2个进程开始,使用sendMessage/4将消息Message传递M次,其它的函数应该很简单,读者自行去体验,代码如下:

-module(ring0).
-export([start/3,genProcess/2,createProcess/2,loop/1,sendMessage/4,sleep/1,sendDie/1]).

start(M,N,Message) ->
    Max = N,
    createProcess(N,Max),
    %% Process1 send M number of messages to next M process
    sendMessage(2,M,Message,Max),
    sleep(1000),
    io:format("~nRing transfer success!~n").
        
createProcess(N,Max) ->
    L = for(N,fun(N) -> genProcess(N,Max)end ).

for(1,F) -> [F(1)];
for(I,F) -> [F(I)|for(I-1,F)].

genProcess(N,Max) ->
    ProN = genAtom(N),
    register(ProN,spawn(fun()-> loop(Max) end)),
    io:format("process [~p] (~p) was created success!~n",[ProN,whereis(ProN)]).

loop(Max) ->
    receive
        die ->
            quit;
        {From, {X,Y,Z}} ->
            io:format("Message (~p) From-To: (~p) to (~p)~n",[Z,From,self()]),
            if
                Y =:= 0 ->
                    %quit;
                    io:format("i am here~n");
                Y =/= 0 ->
                    ProM = genAtom(X),
                    sendMessage(X,Y-1,Z,Max)
                    %sleep(3000),
                    %ProM ! {self(),{X,Y,Z}}
            end,
            loop(Max)
    end.

%%向Process N 发送一条消息,此消息需要经过M步
sendMessage(N,M,Message,Max) ->
    if
        N =:= 1 ->
            Pid1 = whereis(genAtom(Max)),
            Pid2 = whereis(genAtom(N));
        N =/= 1 ->
            Pid1 = whereis(genAtom(N-1)),
            Pid2 = whereis(genAtom(N))
    end,
    %%io:format("pid1= (~p)  pid2 =(~p)~n",[Pid1,Pid2]),
    if 
        M =:= 0 ->
            quit;
        M =/= 0 ->
            %% io:format("---Message (~p) From-To: (~p) to (~p)~n",[Message,Pid1,Pid2]),
            if 
                N =:= Max ->
                        io:format("Pass 1~n"),
                        Pid2 ! {Pid1, {1, M,Message}};
                        %sendMessage(1, M-1, Message,Max),
                N =/= Max  ->
                        io:format("Pass 2~n"),
                        Pid2 ! {Pid1, {N+1, M,Message}}
                        %sendMessage(N+1,M-1,Message,Max)
            end
    end.
    
    
genAtom(N) ->
    Temp = lists:concat([process,N]),
    Ret = list_to_atom(Temp).

sendDie(N) ->
    ProN = genAtom(N),
    ProN ! die,
    if 
        N =:= 1 ->
            quit;
        N =/= 1 ->
            sendDie(N-1)
    end.

sleep(T) ->
    receive
    after T ->
        true
    end.

本节主要通过2个进程创建于消息传递的例子,对Erlang系统消息传递机制进行了实战的讲解分析,通过代码分析看来,Erlang消息传递过程比较简单,无非是发送与接收的通信。真应了那句:“周瑜打黄盖——一个愿打一个愿挨”,消息传递也是这样,只有你给我发消息的时候我才能知道你对我有意思。

posted @ 2012-05-05 17:07  chinagragon  阅读(2041)  评论(0编辑  收藏  举报

Powered by中国龙 博客空间 IT闲人,不干实事