初次使用erlang的concurrent

如果不是它骇人听闻的并行性能,几乎不会考虑去学习这么一门语言。因为它的并行,我看到的是一块用软件写出来的电路板,是的,它几乎就是把电脑变成了一个可以自由编写逻辑的芯片。

例程来自这里:http://www.erlang.org/doc/getting_started/conc_prog.html

 

例1 体会concurrent

-module(tut14).

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

say_something(What, 0) ->
    done;
say_something(What, Times) ->
    io:format("~p~n", [What]),
    say_something(What, Times - 1).

start() ->
    spawn(tut14, say_something, [hello, 3]),
    spawn(tut14, say_something, [goodbye, 3]).

我们看到,除了最后两行,这其实和我们前面学到的没什么两样。。。最后两行出现了一个新鲜的BIF,spawn(),他有三个参数:

1. 参数2所在的模块名

2. 启动新进程后,执行哪个函数

3. 要传递给参数2的参数

两个spawn()事实上只启用了一个新的进程,一个用来执行say_something(hello, 3),一个用来执行say_something(goodbye, 3)。当然,他们是在同时执行的:

> c(tut14).
{ok,tut14}
> tut14:say_something(hello, 3).
hello
hello
hello
done
> tut14:start().
hello
goodbye
<0.39.0>
hello
goodbye
hello
goodbye

 

例2 发送和接收消息

通常意义上大家认为进程是独立运行的,不共享任何资源;而线程是需要共享资源的。我们不共享资源,所以把这里并行的叫做进程。但是,既然不共享资源,那该如何进行进程间通信呢?事实上,机制是唯一的:消息。我们可以根据进程的pid来发送消息,比如上面的<0.39.0>就是进程的pid。

-module(tut15).
-export([start/0, ping/2, pong/0]).

ping(0, Pong_PID) ->
    Pong_PID ! finished,
    io:format("ping finished~n", []);

ping(N, Pong_PID) ->
    Pong_PID ! {ping, self()},
    receive
        pong ->
            io:format("Ping received pong~n", [])
    end,
    ping(N - 1, Pong_PID).

pong() ->
    receive
        finished ->
            io:format("Pong finished~n", []);
        {ping, Ping_PID} ->
            io:format("Pong received ping~n", []),
            Ping_PID ! pong,
            pong()
    end.

start() ->
    Pong_PID = spawn(tut15, pong, []),
    spawn(tut15, ping, [3, Pong_PID]).

上面的代码里出现了两个生面孔:

1、Pong_PID ! finished。这就是前面提到的发送message。

2、receive...end。这句则是用来接收message;如pong()中的finished和{ping, Ping_PID}则是两项匹配条件,表示如果接收到的消息是这个或者那个,然后如何如何。如果接收到的消息是finished,那么在io中输出,pongfinished。

3、Pong_PID是由spawn返回的,而Ping_PID则是调用self()函数获取的。

执行的结果是:

> c("tut15").
{ok,tut15}
> tut15:
module_info/0  module_info/1  ping/2         pong/0         start/0        

> tut15:start().
Pong received ping
<0.47.0>
Ping received pong 
Pong received ping
Ping received pong 
Pong received ping
Ping received pong 
ping finished 
Pong finished

初次之外,还有一个“别名”机制,我们使用register,来给进程起个名字,这样我们在发消息的时候,就不再是依据PID,使用名字就可以了。我们还是使用上面的例子,只是引入了register,而不再用Pong_PID:

-module(tut15).

-export([start/0, ping/1, pong/0]).

ping(0) ->
    pong ! finished,
    io:format("ping finished~n", []);
...

start() ->
    register(pong, spawn(tut15, pong, [])),
    spawn(tut15, ping, [3]).

如上:register(some_atom, Pid),第一个参数是一个Atom,第二个参数是spawn返回来的进程id。

 

窥一斑而知全豹。

posted @ 2014-05-07 23:16  Biiigfish  阅读(289)  评论(0编辑  收藏  举报