erlang-并发编程_1、创建进程、进程中消息的传递、注册进程名称

写在前面

本文主要是以一个erlang的学习记录,有错误的地方欢迎指正。


erlang-并发编程_1、创建进程、进程中消息的传递、注册进程名称_第1张图片
erlang学习脑图

1.关于并发

串行是有很多任务要做,但要先完成一项之后才能,做接下去做另一项任务;
并发是指同时有很多的任务要去做,可以串行处理,也可以并行处理;
并行是指同时一起做多个任务。

2.创建进程

示例1:
使用erlang:spawn/1,2,3,4来创建一个erlang进程
在erlang shell 中输入


6> HelloSpawn = fun() -> io:format("hello Spawn") 
end.
%定义一个函数匹配给一个变量
#Fun
7> spawn(HelloSpawn).
%spawn/1 BIF方法创建用一个函数做为一个参数数的进程
hello Spawn<0.41.0>
8> PID = pid(0.41.0).%符号输入错误导致语法报错
* 1: syntax error before: 0
8> PID = pid(0.41,0).%符号输入错误导致语法报异常
** exception error: undefined shell command pid/2
9> PID = pid(0,41,0).%检查是否是PID类型
<0.41.0>
10> is_pid(PID).
true
11> is_process_alive(PID).%%检查进程是否还活着
false
12> 

示例2:
运用内置函数spawn(Module,Exported_Function,list of Arguments)
新建进程示例:
新建文件tut14.erl,代码如下:

-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]).

命令窗口输入如下:

➜  erlang erl
Erlang R15B03 (erts-5.9.3.1) [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9.3.1  (abort with ^G)
1> c(tut14).
tut14.erl:7: Warning: variable 'What' is unused
{ok,tut14}
2> tut14:s
say_something/2  start/0          
2> tut14:say_something(hello123,3).
%%直接调用函数打出内容
hello123
hello123
hello123
done
3> tut14:start().  
%调用start()函数打出内容,                
hello
goodbye
<0.40.0>
%启用一个新的进程,并发处理
hello
goodbye
hello
goodbye

3.消息的传递

实现内容1:
从自己进程的信箱里发送消息和读取消息

注:erlang shell 也是一个进程,也有自已的pid.

17> self().%%self/1 返回当前进程的pid
<0.55.0>
18> 1=2.    %输入错误的对应关系,使当前的shell崩溃报错。
** exception error: no match of right hand side value 2
19> self(). %再查当前的进程pid,说明shell崩溃后重新启动了一个新的进程
<0.59.0>
20> 

3.1消息的发送

使用消息发送运算符!发送消息

20> self() ! "hello".
%向自已所在的进程发送一个list类型的“hello”
"hello"
21> flush().
% flush()将当前process(进程)的信箱里的内容清空并打印
Shell got "hello"
ok
22> 

3.2读取消息

receive ... end 语名使用pattern matching(匹配)来从自已的进程的信箱里读取消息,可以使用after语名来设置等待超时时间

38> self() ! "hello1".
"hello1"
39> self() ! "hello2".
"hello2"
40> self() ! "hello3".
"hello3"
41> receive Hello -> Hello after 3000 -> no_more end.
%% 读取任意消息并返回这条消息,如果信箱里没有消息了,等待 3 秒后结束并返回 no_more.
"hello1"
42> receive Hello -> Hello after 3000 -> no_more end.
no_more
43> receive Hello -> Hello after 3000 -> no_more end.
no_more
 %% 后面这两条为什么返回 no_more ? 不应该是 "hello2", "hello3" 吗?
44> 
44> flush().%打开信箱里的所有消息并清空
Shell got "hello2"
Shell got "hello3"
ok

上面的第 41 行 receive 语句里,erlang shell 进程查看邮箱,查到第一个消息是 "hello1",Hello 被绑定为 "hello1"。再次运行 receive 语句的时候,由于 Hello 的值已经为 "hello1",与信箱里的 "hello2", "hello3" 都不匹配,所以后面两条 receive 语句都没有从信箱里读取新消息,"hello2" 和 "hello2" 仍然存储在信箱里:

4.消息传递进阶

创建了两个进程,它们相互之间会发送多个消息
新建一个tut15.erl 文件,代码如下:

-module(tut15).

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

ping(0,Pong_PID) ->
    Pong_PID ! finished,
    %向传过来的PID发送消息
    io:format("ping finished~n",[]);

ping(N,Pong_PID) ->
    Pong_PID ! {ping,self()},
    %向传过来的PID发送消息
    receive
        %%接收到传过来的消息,收到的消息为pong时,输入内容
        pong ->
            io:format("ping recevied pong~n",[])
    end,
    %重复调用,直到为N-1 为0
    ping(N - 1,Pong_PID).
        
pong() ->
    receive 
        finished -> %收到的消息为finished 时输入内容
            io:format("Pong finish ~n",[]);
        {ping,Ping_PID} ->
            io:format("Pong received ping~n",[]),
            Ping_PID ! pong,
            %向传过来的PID发送消息
            pong()%%自已调用自已,直到接收到finished,结束
    end.

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

命令窗口输入命令如下:

4> c(tut15).
{ok,tut15}
5> tut15:start().
Pong received ping
<0.51.0>
ping recevied pong
Pong received ping
ping recevied pong
Pong received ping
ping recevied pong
ping finished
Pong finish 
6> 

5.Erlang 注册进程名称

Erlang 提供了为每个进程提供一个名称绑定的机制,这样进程间通信就可以通过进程名来实现,而不需要知道进程的进程标识符了。为每个进程注册一个名称需要用到内置函数 register:
关键代码:register(some_atom, Pid)

新建tut16.erl文件,代码如下:

-module(tut16).

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

ping(0) ->
    pong ! finished,
    %发送信息
    io:format("ping finished~n",[]);

ping(N) ->
    pong ! {ping,self()},
    %发送信息,当前shell进程
    receive
        %接收消息并打印
        pong ->
            io:format("Ping received pong~n",[])
    end,
    ping(N - 1).

pong() ->
    receive
        finished ->
            %接收消息并打印
            io:format("pong finished~n",[]);
        {ping,Ping_PID} ->
            %接收消息并打印
            io:format("pong received ping~n",[]),
            Ping_PID ! pong,
            pong()
    end.

start() ->
    register(pong,spawn(tut16,pong,[])),
    %注册一个进程,命为pong
    spawn(tut16,ping,[3]).

命令窗口输入命令如下:

9> 
9> c(tut16).     
{ok,tut16}
10> tut16:start().
pong received ping
<0.71.0>
Ping received pong
pong received ping
Ping received pong
pong received ping
Ping received pong
ping finished
pong finished
11> 

写在后面

引用网络博客内容:
https://www.jianshu.com/p/b45eb9314d1e (30 分钟学 Erlang (一))
https://www.w3cschool.cn/erlang/tohb1p5z.html (w3cschool erlang教程)

个人博客地址:https://zhangyongfeng1.github.io/
地址:https://www.jianshu.com/u/137f325832fb

你可能感兴趣的:(erlang-并发编程_1、创建进程、进程中消息的传递、注册进程名称)