写在前面
本文主要是以一个erlang的学习记录,有错误的地方欢迎指正。
1.关于并发
串行是有很多任务要做,但要先完成一项之后才能,做接下去做另一项任务;
并发是指同时有很多的任务要去做,可以串行处理,也可以并行处理;
并行是指同时一起做多个任务。
2.创建进程
示例1:
使用erlang:spawn/1,2,3,4来创建一个erlang进程
在erlang shell 中输入
6> HelloSpawn = fun() -> io:format("hello Spawn")
end.
%定义一个函数匹配给一个变量
#Fun<erl_eval.20.82930912>
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